Combine visualizations and visualize plugins (#121550)

* [WIP] Combine visualizations and visualize plugins

* Revert some changes and do some refactoring

* Refactor some code

* Fix some tests

* Fix functional tests and some jest test cases

* Update telemetry

* Fix get_visualization_instance.test and plugin-list.asciidoc

* Refactor some code

* fix CI

* Add visualizations to vis_default_editor tsconfig

* Revert changes related to telemetry and permissions

* Add dashboard to timeseries tsconfig.json

* Update limits file

* Update translation keys

* Add capabilitiesProvider back to server and replace visEditorsRegistry getter and setter with service

* Update mocks.ts

* Revert changes related to visEditorsRegistry

* Get rid of visEditorsRegistry getter and setter

* Remove dashboard from timeseries/tsconfig.json

* Return back dashboard dependency to timeseries/tsconfig.json, rename applicaion folder to visualize_app and APP_NAME to VISUALIZE_APP_NAME, revert types.ts

* Remove comma in .i18nrc.json

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Alexey Antonov <alexwizp@gmail.com>
This commit is contained in:
Diana Derevyankina 2022-01-12 16:49:22 +03:00 committed by GitHub
parent b34476e659
commit a9ec1be357
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
86 changed files with 688 additions and 968 deletions

View file

@ -77,8 +77,7 @@
"visTypeVega": "src/plugins/vis_types/vega",
"visTypeVislib": "src/plugins/vis_types/vislib",
"visTypeXy": "src/plugins/vis_types/xy",
"visualizations": "src/plugins/visualizations",
"visualize": "src/plugins/visualize"
"visualizations": "src/plugins/visualizations"
},
"translations": []
}

View file

@ -342,10 +342,6 @@ The plugin exposes the static DefaultEditorController class to consume.
|WARNING: Missing README.
|{kib-repo}blob/{branch}/src/plugins/visualize[visualize]
|WARNING: Missing README.
|===
[discrete]

View file

@ -71,7 +71,6 @@ pageLoadAssetSize:
visTypeVislib: 242838
visTypeXy: 113478
visualizations: 90000
visualize: 57431
watcher: 43598
runtimeFields: 41752
stackAlerts: 29684

View file

@ -2,7 +2,7 @@
"id": "visDefaultEditor",
"version": "kibana",
"ui": true,
"optionalPlugins": ["visualize"],
"optionalPlugins": ["visualizations"],
"requiredBundles": ["kibanaUtils", "kibanaReact", "data", "fieldFormats", "discover", "esUiShared"],
"owner": {
"name": "Vis Editors",

View file

@ -13,8 +13,11 @@ import React, { useEffect, useRef, useState, useCallback } from 'react';
import { EventEmitter } from 'events';
import { EuiResizableContainer } from '@elastic/eui';
import { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public';
import { EditorRenderProps } from 'src/plugins/visualize/public';
import {
Vis,
VisualizeEmbeddableContract,
EditorRenderProps,
} from 'src/plugins/visualizations/public';
import { KibanaContextProvider } from '../../kibana_react/public';
import { Storage } from '../../kibana_utils/public';

View file

@ -12,7 +12,7 @@ import { EventEmitter } from 'events';
import { EuiErrorBoundary, EuiLoadingChart } from '@elastic/eui';
import { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public';
import { IEditorController, EditorRenderProps } from 'src/plugins/visualize/public';
import { IEditorController, EditorRenderProps } from 'src/plugins/visualizations/public';
import { KibanaThemeProvider } from '../../kibana_react/public';
import { getTheme } from './services';

View file

@ -8,21 +8,21 @@
import { CoreSetup, Plugin } from 'kibana/public';
import { VisualizePluginSetup } from '../../visualize/public';
import { DefaultEditorController } from './default_editor_controller';
import { setTheme } from './services';
import type { VisualizationsSetup } from '../../visualizations/public';
export interface VisDefaultEditorSetupDependencies {
visualize: VisualizePluginSetup;
visualizations: VisualizationsSetup;
}
export class VisDefaultEditorPlugin
implements Plugin<void, void, VisDefaultEditorSetupDependencies, {}>
{
public setup(core: CoreSetup, { visualize }: VisDefaultEditorSetupDependencies) {
public setup(core: CoreSetup, { visualizations }: VisDefaultEditorSetupDependencies) {
setTheme(core.theme);
if (visualize) {
visualize.visEditorsRegistry.registerDefault(DefaultEditorController);
if (visualizations) {
visualizations.visEditorsRegistry.registerDefault(DefaultEditorController);
}
}

View file

@ -12,7 +12,8 @@
"references": [
{ "path": "../../core/tsconfig.json" },
{ "path": "../data/tsconfig.json" },
{ "path": "../visualize/tsconfig.json" },
{ "path": "../visualizations/tsconfig.json" },
{ "path": "../discover/tsconfig.json" },
{ "path": "../kibana_utils/tsconfig.json" },
{ "path": "../kibana_react/tsconfig.json" },
{ "path": "../field_formats/tsconfig.json" }

View file

@ -4,7 +4,7 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["charts", "data", "expressions", "visualizations", "visualize"],
"requiredPlugins": ["charts", "data", "expressions", "visualizations"],
"optionalPlugins": ["home","usageCollection"],
"requiredBundles": ["kibanaUtils", "kibanaReact", "fieldFormats"],
"owner": {

View file

@ -32,7 +32,7 @@ import { fetchFields, VisFields } from '../lib/fetch_fields';
import { getDataStart, getCoreStart } from '../../services';
import type { TimeseriesVisParams } from '../../types';
import { UseIndexPatternModeCallout } from './use_index_patter_mode_callout';
import type { EditorRenderProps } from '../../../../../visualize/public';
import type { EditorRenderProps } from '../../../../../visualizations/public';
const VIS_STATE_DEBOUNCE_DELAY = 200;
const APP_NAME = 'VisEditor';

View file

@ -9,9 +9,12 @@
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import type { EventEmitter } from 'events';
import type { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public';
import type { IEditorController, EditorRenderProps } from 'src/plugins/visualize/public';
import type {
Vis,
VisualizeEmbeddableContract,
IEditorController,
EditorRenderProps,
} from 'src/plugins/visualizations/public';
import { getUISettings, getI18n, getCoreStart } from '../services';
import { VisEditor } from './components/vis_editor_lazy';
import type { TimeseriesVisParams } from '../types';

View file

@ -9,7 +9,6 @@
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public';
import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public';
import { VisualizationsSetup } from '../../../visualizations/public';
import { VisualizePluginSetup } from '../../../visualize/public';
import { EditorController, TSVB_EDITOR_NAME } from './application/editor_controller';
import { createMetricsFn } from './metrics_fn';
@ -30,7 +29,6 @@ import { getTimeseriesVisRenderer } from './timeseries_vis_renderer';
export interface MetricsPluginSetupDependencies {
expressions: ReturnType<ExpressionsPublicPlugin['setup']>;
visualizations: VisualizationsSetup;
visualize: VisualizePluginSetup;
}
/** @internal */
@ -47,11 +45,8 @@ export class MetricsPlugin implements Plugin<void, void> {
this.initializerContext = initializerContext;
}
public setup(
core: CoreSetup,
{ expressions, visualizations, visualize }: MetricsPluginSetupDependencies
) {
visualize.visEditorsRegistry.register(TSVB_EDITOR_NAME, EditorController);
public setup(core: CoreSetup, { expressions, visualizations }: MetricsPluginSetupDependencies) {
visualizations.visEditorsRegistry.register(TSVB_EDITOR_NAME, EditorController);
expressions.registerFunction(createMetricsFn);
expressions.registerRenderer(
getTimeseriesVisRenderer({

View file

@ -18,7 +18,7 @@
{ "path": "../../data/tsconfig.json" },
{ "path": "../../expressions/tsconfig.json" },
{ "path": "../../visualizations/tsconfig.json" },
{ "path": "../../visualize/tsconfig.json" },
{ "path": "../../dashboard/tsconfig.json" },
{ "path": "../../kibana_utils/tsconfig.json" },
{ "path": "../../kibana_react/tsconfig.json" },
{ "path": "../../usage_collection/tsconfig.json" },

View file

@ -8,3 +8,19 @@
export const VISUALIZE_ENABLE_LABS_SETTING = 'visualize:enableLabs';
export const VISUALIZE_EMBEDDABLE_TYPE = 'visualization';
export const STATE_STORAGE_KEY = '_a';
export const GLOBAL_STATE_STORAGE_KEY = '_g';
export const VISUALIZE_APP_NAME = 'visualize';
export const VisualizeConstants = {
VISUALIZE_BASE_PATH: '/app/visualize',
LANDING_PAGE_PATH: '/',
WIZARD_STEP_1_PAGE_PATH: '/new',
WIZARD_STEP_2_PAGE_PATH: '/new/configure',
CREATE_PATH: '/create',
EDIT_PATH: '/edit',
EDIT_BY_VALUE_PATH: '/edit_by_value',
APP_ID: 'visualize',
};

View file

@ -17,7 +17,7 @@ import type { LocatorDefinition, LocatorPublic } from 'src/plugins/share/common'
import { isFilterPinned } from '../../data/common';
import { url } from '../../kibana_utils/common';
import { GLOBAL_STATE_STORAGE_KEY, STATE_STORAGE_KEY, VisualizeConstants } from './constants';
import { PureVisState } from './types';
import type { SavedVisState } from './types';
const removeEmptyKeys = (o: Record<string, Serializable>): Record<string, Serializable> =>
omitBy(o, (v) => v == null);
@ -59,7 +59,7 @@ export type VisualizeLocatorParams = {
*
* @note This is required to navigate to "create" page (i.e., when no `visId` has been provided).
*/
vis?: PureVisState;
vis?: SavedVisState;
/**
* Whether this visualization is linked a saved search.

View file

@ -7,12 +7,15 @@
"data",
"expressions",
"uiActions",
"urlForwarding",
"navigation",
"embeddable",
"inspector",
"savedObjects"
"savedObjects",
"presentationUtil"
],
"optionalPlugins": ["usageCollection", "spaces", "savedObjectsTaggingOss"],
"requiredBundles": ["kibanaUtils", "discover", "kibanaReact"],
"optionalPlugins": [ "home", "share", "usageCollection", "spaces", "savedObjectsTaggingOss"],
"requiredBundles": ["kibanaUtils", "discover", "kibanaReact", "home"],
"extraPublicDirs": ["common/constants", "common/prepare_log_table", "common/expression_functions"],
"owner": {
"name": "Vis Editors",

View file

@ -55,3 +55,5 @@ export type {
HistogramParams,
} from '../common/expression_functions/xy_dimension';
export { urlFor, getFullPath } from './utils/saved_visualize_utils';
export type { IEditorController, EditorRenderProps } from './visualize_app/types';

View file

@ -19,12 +19,16 @@ import { usageCollectionPluginMock } from '../../../plugins/usage_collection/pub
import { uiActionsPluginMock } from '../../../plugins/ui_actions/public/mocks';
import { inspectorPluginMock } from '../../../plugins/inspector/public/mocks';
import { savedObjectsPluginMock } from '../../../plugins/saved_objects/public/mocks';
import { urlForwardingPluginMock } from '../../../plugins/url_forwarding/public/mocks';
import { navigationPluginMock } from '../../../plugins/navigation/public/mocks';
import { presentationUtilPluginMock } from '../../../plugins/presentation_util/public/mocks';
import { savedObjectTaggingOssPluginMock } from '../../saved_objects_tagging_oss/public/mocks';
const createSetupContract = (): VisualizationsSetup => ({
createBaseVisualization: jest.fn(),
registerAlias: jest.fn(),
hideTypes: jest.fn(),
visEditorsRegistry: { registerDefault: jest.fn(), register: jest.fn(), get: jest.fn() },
});
const createStartContract = (): VisualizationsStart => ({
@ -33,16 +37,7 @@ const createStartContract = (): VisualizationsStart => ({
getAliases: jest.fn(),
getByGroup: jest.fn(),
unRegisterAlias: jest.fn(),
getSavedVisualization: jest.fn(),
saveVisualization: jest.fn(),
findListItems: jest.fn(),
showNewVisModal: jest.fn(),
createVis: jest.fn(),
convertFromSerializedVis: jest.fn(),
convertToSerializedVis: jest.fn(),
__LEGACY: {
createVisEmbeddableFromObject: jest.fn(),
},
});
const createInstance = async () => {
@ -54,6 +49,7 @@ const createInstance = async () => {
expressions: expressionsPluginMock.createSetupContract(),
inspector: inspectorPluginMock.createSetupContract(),
usageCollection: usageCollectionPluginMock.createSetupContract(),
urlForwarding: urlForwardingPluginMock.createSetupContract(),
});
const doStart = () =>
plugin.start(coreMock.createStart(), {
@ -68,6 +64,9 @@ const createInstance = async () => {
savedObjectsClient: coreMock.createStart().savedObjects.client,
savedObjects: savedObjectsPluginMock.createStartContract(),
savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(),
navigation: navigationPluginMock.createStartContract(),
presentationUtil: presentationUtilPluginMock.createStartContract(coreMock.createStart()),
urlForwarding: urlForwardingPluginMock.createStartContract(),
});
return {

View file

@ -6,7 +6,17 @@
* Side Public License, v 1.
*/
import type { SavedObjectsFindOptionsReference } from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { filter, map } from 'rxjs/operators';
import { createHashHistory } from 'history';
import { BehaviorSubject } from 'rxjs';
import {
AppMountParameters,
AppUpdater,
DEFAULT_APP_CATEGORIES,
ScopedHistory,
} from '../../../core/public';
import { VisualizeConstants } from '../common/constants';
import {
setUISettings,
setTypes,
@ -28,28 +38,29 @@ import {
setTheme,
} from './services';
import {
createVisEmbeddableFromObject,
VISUALIZE_EMBEDDABLE_TYPE,
VisualizeEmbeddableFactory,
createVisEmbeddableFromObject,
} from './embeddable';
import type { SpacesPluginStart } from '../../../../x-pack/plugins/spaces/public';
import { TypesService } from './vis_types/types_service';
import { range as rangeExpressionFunction } from '../common/expression_functions/range';
import { visDimension as visDimensionExpressionFunction } from '../common/expression_functions/vis_dimension';
import { xyDimension as xyDimensionExpressionFunction } from '../common/expression_functions/xy_dimension';
import { createStartServicesGetter, StartServicesGetter } from '../../kibana_utils/public';
import type { SerializedVis, Vis } from './vis';
import { showNewVisModal } from './wizard';
import {
convertFromSerializedVis,
convertToSerializedVis,
getSavedVisualization,
saveVisualization,
findListItems,
} from './utils/saved_visualize_utils';
createKbnUrlStateStorage,
createKbnUrlTracker,
createStartServicesGetter,
Storage,
withNotifyOnErrors,
} from '../../kibana_utils/public';
import { VisualizeLocatorDefinition } from '../common/locator';
import { showNewVisModal } from './wizard';
import { createVisEditorsRegistry, VisEditorsRegistry } from './vis_editors_registry';
import { esFilters } from '../../../plugins/data/public';
import { FeatureCatalogueCategory } from '../../home/public';
import type { VisualizeServices } from './visualize_app/types';
import type {
PluginInitializerContext,
CoreSetup,
@ -70,8 +81,13 @@ import type { DataPublicPluginSetup, DataPublicPluginStart } from '../../../plug
import type { ExpressionsSetup, ExpressionsStart } from '../../expressions/public';
import type { EmbeddableSetup, EmbeddableStart } from '../../embeddable/public';
import type { SavedObjectTaggingOssPluginStart } from '../../saved_objects_tagging_oss/public';
import { createVisAsync } from './vis_async';
import type { VisSavedObject, SaveVisOptions, GetVisOptions } from './types';
import type { NavigationPublicPluginStart as NavigationStart } from '../../navigation/public';
import type { SharePluginSetup, SharePluginStart } from '../../share/public';
import type { UrlForwardingSetup, UrlForwardingStart } from '../../url_forwarding/public';
import type { PresentationUtilPluginStart } from '../../presentation_util/public';
import type { UsageCollectionStart } from '../../usage_collection/public';
import type { HomePublicPluginSetup } from '../../home/public';
import type { SpacesPluginStart } from '../../../../x-pack/plugins/spaces/public';
/**
* Interface for this plugin's returned setup/start contracts.
@ -79,21 +95,10 @@ import type { VisSavedObject, SaveVisOptions, GetVisOptions } from './types';
* @public
*/
export type VisualizationsSetup = TypesSetup;
export type VisualizationsSetup = TypesSetup & { visEditorsRegistry: VisEditorsRegistry };
export interface VisualizationsStart extends TypesStart {
createVis: (visType: string, visState: SerializedVis) => Promise<Vis>;
convertToSerializedVis: typeof convertToSerializedVis;
convertFromSerializedVis: typeof convertFromSerializedVis;
showNewVisModal: typeof showNewVisModal;
getSavedVisualization: (opts?: GetVisOptions | string) => Promise<VisSavedObject>;
saveVisualization: (savedVis: VisSavedObject, saveOptions: SaveVisOptions) => Promise<string>;
findListItems: (
searchTerm: string,
listingLimit: number,
references?: SavedObjectsFindOptionsReference[]
) => Promise<{ hits: Array<Record<string, unknown>>; total: number }>;
__LEGACY: { createVisEmbeddableFromObject: ReturnType<typeof createVisEmbeddableFromObject> };
}
export interface VisualizationsSetupDeps {
@ -102,6 +107,9 @@ export interface VisualizationsSetupDeps {
expressions: ExpressionsSetup;
inspector: InspectorSetup;
usageCollection: UsageCollectionSetup;
urlForwarding: UrlForwardingSetup;
home?: HomePublicPluginSetup;
share?: SharePluginSetup;
}
export interface VisualizationsStartDeps {
@ -112,10 +120,15 @@ export interface VisualizationsStartDeps {
uiActions: UiActionsStart;
application: ApplicationStart;
getAttributeService: EmbeddableStart['getAttributeService'];
navigation: NavigationStart;
presentationUtil: PresentationUtilPluginStart;
savedObjects: SavedObjectsStart;
savedObjectsClient: SavedObjectsClientContract;
spaces?: SpacesPluginStart;
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
share?: SharePluginStart;
urlForwarding: UrlForwardingStart;
usageCollection?: UsageCollectionStart;
}
/**
@ -136,15 +149,175 @@ export class VisualizationsPlugin
>
{
private readonly types: TypesService = new TypesService();
private getStartServicesOrDie?: StartServicesGetter<VisualizationsStartDeps, VisualizationsStart>;
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
private stopUrlTracking: (() => void) | undefined = undefined;
private currentHistory: ScopedHistory | undefined = undefined;
private isLinkedToOriginatingApp: (() => boolean) | undefined = undefined;
constructor(initializerContext: PluginInitializerContext) {}
constructor(private initializerContext: PluginInitializerContext) {}
public setup(
core: CoreSetup<VisualizationsStartDeps, VisualizationsStart>,
{ expressions, embeddable, usageCollection, data }: VisualizationsSetupDeps
{
expressions,
embeddable,
usageCollection,
data,
home,
urlForwarding,
share,
}: VisualizationsSetupDeps
): VisualizationsSetup {
const start = (this.getStartServicesOrDie = createStartServicesGetter(core.getStartServices));
const {
appMounted,
appUnMounted,
stop: stopUrlTracker,
setActiveUrl,
restorePreviousUrl,
} = createKbnUrlTracker({
baseUrl: core.http.basePath.prepend(VisualizeConstants.VISUALIZE_BASE_PATH),
defaultSubUrl: '#/',
storageKey: `lastUrl:${core.http.basePath.get()}:visualize`,
navLinkUpdater$: this.appStateUpdater,
toastNotifications: core.notifications.toasts,
stateParams: [
{
kbnUrlKey: '_g',
stateUpdate$: data.query.state$.pipe(
filter(
({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval)
),
map(({ state }) => ({
...state,
filters: state.filters?.filter(esFilters.isFilterPinned),
}))
),
},
],
getHistory: () => this.currentHistory!,
onBeforeNavLinkSaved: (urlToSave: string) => {
if (this.isLinkedToOriginatingApp?.()) {
return core.http.basePath.prepend(VisualizeConstants.VISUALIZE_BASE_PATH);
}
return urlToSave;
},
});
this.stopUrlTracking = () => {
stopUrlTracker();
};
const start = createStartServicesGetter(core.getStartServices);
const visEditorsRegistry = createVisEditorsRegistry();
core.application.register({
id: VisualizeConstants.APP_ID,
title: 'Visualize Library',
order: 8000,
euiIconType: 'logoKibana',
defaultPath: '#/',
category: DEFAULT_APP_CATEGORIES.kibana,
updater$: this.appStateUpdater.asObservable(),
// remove all references to visualize
mount: async (params: AppMountParameters) => {
const [coreStart, pluginsStart] = await core.getStartServices();
this.currentHistory = params.history;
// allows the urlTracker to only save URLs that are not linked to an originatingApp
this.isLinkedToOriginatingApp = () => {
return Boolean(
pluginsStart.embeddable
.getStateTransfer()
.getIncomingEditorState(VisualizeConstants.APP_ID)?.originatingApp
);
};
// make sure the index pattern list is up to date
pluginsStart.data.indexPatterns.clearCache();
// make sure a default index pattern exists
// if not, the page will be redirected to management and visualize won't be rendered
await pluginsStart.data.indexPatterns.ensureDefaultDataView();
appMounted();
// dispatch synthetic hash change event to update hash history objects
// this is necessary because hash updates triggered by using popState won't trigger this event naturally.
const unlistenParentHistory = params.history.listen(() => {
window.dispatchEvent(new HashChangeEvent('hashchange'));
});
/**
* current implementation uses 2 history objects:
* 1. the hash history (used for the react hash router)
* 2. and the scoped history (used for url tracking)
* this should be replaced to use only scoped history after moving legacy apps to browser routing
*/
const history = createHashHistory();
const services: VisualizeServices = {
...coreStart,
history,
kbnUrlStateStorage: createKbnUrlStateStorage({
history,
useHash: coreStart.uiSettings.get('state:storeInSessionStorage'),
...withNotifyOnErrors(coreStart.notifications.toasts),
}),
urlForwarding: pluginsStart.urlForwarding,
pluginInitializerContext: this.initializerContext,
chrome: coreStart.chrome,
data: pluginsStart.data,
localStorage: new Storage(localStorage),
navigation: pluginsStart.navigation,
share: pluginsStart.share,
toastNotifications: coreStart.notifications.toasts,
visualizeCapabilities: coreStart.application.capabilities.visualize,
dashboardCapabilities: coreStart.application.capabilities.dashboard,
embeddable: pluginsStart.embeddable,
stateTransferService: pluginsStart.embeddable.getStateTransfer(),
setActiveUrl,
createVisEmbeddableFromObject: createVisEmbeddableFromObject({ start }),
savedObjectsPublic: pluginsStart.savedObjects,
scopedHistory: params.history,
restorePreviousUrl,
setHeaderActionMenu: params.setHeaderActionMenu,
savedObjectsTagging: pluginsStart.savedObjectsTaggingOss?.getTaggingApi(),
presentationUtil: pluginsStart.presentationUtil,
usageCollection: pluginsStart.usageCollection,
getKibanaVersion: () => this.initializerContext.env.packageInfo.version,
spaces: pluginsStart.spaces,
visEditorsRegistry,
};
params.element.classList.add('visAppWrapper');
const { renderApp } = await import('./visualize_app');
const unmount = renderApp(params, services);
return () => {
data.search.session.clear();
params.element.classList.remove('visAppWrapper');
unlistenParentHistory();
unmount();
appUnMounted();
};
},
});
urlForwarding.forwardApp('visualize', 'visualize');
if (home) {
home.featureCatalogue.register({
id: 'visualize',
title: 'Visualize Library',
description: i18n.translate('visualizations.visualizeDescription', {
defaultMessage:
'Create visualizations and aggregate data stores in your Elasticsearch indices.',
}),
icon: 'visualizeApp',
path: `/app/visualize#${VisualizeConstants.LANDING_PAGE_PATH}`,
showOnHomePage: false,
category: FeatureCatalogueCategory.DATA,
});
}
if (share) {
share.url.locators.create(new VisualizeLocatorDefinition());
}
setUISettings(core.uiSettings);
setUsageCollector(usageCollection);
@ -158,6 +331,7 @@ export class VisualizationsPlugin
return {
...this.types.setup(),
visEditorsRegistry,
};
}
@ -171,6 +345,7 @@ export class VisualizationsPlugin
savedObjects,
spaces,
savedObjectsTaggingOss,
usageCollection,
}: VisualizationsStartDeps
): VisualizationsStart {
const types = this.types.start();
@ -196,46 +371,13 @@ export class VisualizationsPlugin
return {
...types,
showNewVisModal,
getSavedVisualization: async (opts) => {
return getSavedVisualization(
{
search: data.search,
savedObjectsClient: core.savedObjects.client,
dataViews: data.dataViews,
spaces,
savedObjectsTagging: savedObjectsTaggingOss?.getTaggingApi(),
},
opts
);
},
saveVisualization: async (savedVis, saveOptions) => {
return saveVisualization(savedVis, saveOptions, {
savedObjectsClient: core.savedObjects.client,
overlays: core.overlays,
savedObjectsTagging: savedObjectsTaggingOss?.getTaggingApi(),
});
},
findListItems: async (searchTerm, listingLimit, references) => {
return findListItems(core.savedObjects.client, types, searchTerm, listingLimit, references);
},
/**
* creates new instance of Vis
* @param {IndexPattern} indexPattern - index pattern to use
* @param {VisState} visState - visualization configuration
*/
createVis: async (visType: string, visState: SerializedVis) =>
await createVisAsync(visType, visState),
convertToSerializedVis,
convertFromSerializedVis,
__LEGACY: {
createVisEmbeddableFromObject: createVisEmbeddableFromObject({
start: this.getStartServicesOrDie!,
}),
},
};
}
public stop() {
this.types.stop();
if (this.stopUrlTracking) {
this.stopUrlTracking();
}
}
}

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { VisEditorConstructor } from './application/types';
import { VisEditorConstructor } from './visualize_app/types';
const DEFAULT_NAME = 'default';

View file

@ -20,7 +20,7 @@ import {
VisualizeNoMatch,
VisualizeByValueEditor,
} from './components';
import { VisualizeConstants } from './visualize_constants';
import { VisualizeConstants } from '../../common/constants';
export interface VisualizeAppProps {
onAppLeave: AppMountParameters['onAppLeave'];

View file

@ -14,7 +14,7 @@ export const InfoComponent = () => {
const title = (
<>
<FormattedMessage
id="visualize.experimentalVisInfoText"
id="visualizations.experimentalVisInfoText"
defaultMessage="This visualization is experimental and is not subject to the support SLA of official GA features.
For feedback, please create an issue in {githubLink}."
values={{

View file

@ -26,20 +26,20 @@ export const SplitChartWarning = () => {
data-test-subj="vizSplitChartWarning"
title={
<FormattedMessage
id="visualize.newHeatmapChart.notificationMessage"
id="visualizations.newHeatmapChart.notificationMessage"
defaultMessage="The new heatmap charts library does not yet support split chart aggregation. {conditionalMessage}"
values={{
conditionalMessage: (
<>
{canEditAdvancedSettings && (
<FormattedMessage
id="visualize.newHeatmapChart.conditionalMessage.newLibrary"
id="visualizations.newHeatmapChart.conditionalMessage.newLibrary"
defaultMessage="Switch to the old library in {link}"
values={{
link: (
<EuiLink href={advancedSettingsLink}>
<FormattedMessage
id="visualize.newHeatmapChart.conditionalMessage.advanced settings link"
id="visualizations.newHeatmapChart.conditionalMessage.advancedSettingsLink"
defaultMessage="Advanced Settings."
/>
</EuiLink>
@ -49,7 +49,7 @@ export const SplitChartWarning = () => {
)}
{!canEditAdvancedSettings && (
<FormattedMessage
id="visualize.legacyCharts.conditionalMessage.noPermissions"
id="visualizations.legacyCharts.conditionalMessage.noPermissions"
defaultMessage="Contact your system administrator to switch to the old library."
/>
)}

View file

@ -22,7 +22,7 @@ import {
import { VisualizeServices } from '../types';
import { VisualizeEditorCommon } from './visualize_editor_common';
import { VisualizeAppProps } from '../app';
import { VisualizeConstants } from '../..';
import { VisualizeConstants } from '../../../common/constants';
export const VisualizeByValueEditor = ({ onAppLeave }: VisualizeAppProps) => {
const [originatingApp, setOriginatingApp] = useState<string>();

View file

@ -22,7 +22,7 @@ import {
import { VisualizeServices } from '../types';
import { VisualizeEditorCommon } from './visualize_editor_common';
import { VisualizeAppProps } from '../app';
import { VisualizeConstants } from '../..';
import { VisualizeConstants } from '../../../common/constants';
export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => {
const { id: visualizationIdFromUrl } = useParams<{ id: string }>();

View file

@ -72,7 +72,7 @@ export const VisualizeEditorCommon = ({
const newPath = `${urlFor(newObjectId!)}${services.history.location.search}`;
await services.spaces.ui.redirectLegacyUrl(
newPath,
i18n.translate('visualize.legacyUrlConflict.objectNoun', {
i18n.translate('visualizations.legacyUrlConflict.objectNoun', {
defaultMessage: '{visName} visualization',
values: {
visName: visInstance?.vis?.type.title,
@ -96,7 +96,7 @@ export const VisualizeEditorCommon = ({
const otherObjectId = sharingSavedObjectProps?.aliasTargetId!; // This is always defined if outcome === 'conflict'
const otherObjectPath = `${urlFor(otherObjectId)}${services.history.location.search}`;
return services.spaces.ui.components.getLegacyUrlConflict({
objectNoun: i18n.translate('visualize.legacyUrlConflict.objectNoun', {
objectNoun: i18n.translate('visualizations.legacyUrlConflict.objectNoun', {
defaultMessage: '{visName} visualization',
values: {
visName: visInstance?.vis?.type.title,
@ -144,7 +144,7 @@ export const VisualizeEditorCommon = ({
<h1>
{'savedVis' in visInstance && visInstance.savedVis.id ? (
<FormattedMessage
id="visualize.pageHeading"
id="visualizations.pageHeading"
defaultMessage="{chartName} {chartType} visualization"
values={{
chartName: (visInstance as SavedVisInstance).savedVis.title,
@ -153,7 +153,7 @@ export const VisualizeEditorCommon = ({
/>
) : (
<FormattedMessage
id="visualize.byValue_pageHeading"
id="visualizations.byValue_pageHeading"
defaultMessage="Visualization of type {chartType} embedded into {originatingApp} app"
values={{
chartType: visInstance.vis.type.title,

View file

@ -17,11 +17,14 @@ import useMount from 'react-use/lib/useMount';
import { useLocation } from 'react-router-dom';
import { findListItems } from '../../utils/saved_visualize_utils';
import { showNewVisModal } from '../../wizard';
import { getTypes } from '../../services';
import { SavedObjectsFindOptionsReference } from '../../../../../core/public';
import { useKibana, TableListView } from '../../../../kibana_react/public';
import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../visualizations/public';
import { VisualizeServices } from '../types';
import { VisualizeConstants } from '../visualize_constants';
import { VisualizeConstants } from '../../../common/constants';
import { getTableColumns, getNoItemsMessage } from '../utils';
export const VisualizeListing = () => {
@ -29,10 +32,8 @@ export const VisualizeListing = () => {
services: {
application,
chrome,
dashboard,
history,
toastNotifications,
visualizations,
stateTransferService,
savedObjects,
savedObjectsPublic,
@ -50,7 +51,7 @@ export const VisualizeListing = () => {
useEffect(() => {
if (pathname === '/new') {
// In case the user navigated to the page via the /visualize/new URL we start the dialog immediately
closeNewVisModal.current = visualizations.showNewVisModal({
closeNewVisModal.current = showNewVisModal({
onClose: () => {
// In case the user came via a URL to this page, change the URL to the regular landing page URL after closing the modal
history.push(VisualizeConstants.LANDING_PAGE_PATH);
@ -60,27 +61,27 @@ export const VisualizeListing = () => {
// close modal window if exists
closeNewVisModal.current();
}
}, [history, pathname, visualizations]);
}, [history, pathname]);
useMount(() => {
// Reset editor state for all apps if the visualize listing page is loaded.
stateTransferService.clearEditorState();
chrome.setBreadcrumbs([
{
text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', {
text: i18n.translate('visualizations.visualizeListingBreadcrumbsTitle', {
defaultMessage: 'Visualize Library',
}),
},
]);
chrome.docTitle.change(
i18n.translate('visualize.listingPageTitle', { defaultMessage: 'Visualize Library' })
i18n.translate('visualizations.listingPageTitle', { defaultMessage: 'Visualize Library' })
);
});
useUnmount(() => closeNewVisModal.current());
const createNewVis = useCallback(() => {
closeNewVisModal.current = visualizations.showNewVisModal();
}, [visualizations]);
closeNewVisModal.current = showNewVisModal();
}, []);
const editItem = useCallback(
({ editUrl, editApp }) => {
@ -112,16 +113,18 @@ export const VisualizeListing = () => {
}
const isLabsEnabled = uiSettings.get(VISUALIZE_ENABLE_LABS_SETTING);
return visualizations
.findListItems(searchTerm, listingLimit, references)
.then(({ total, hits }: { total: number; hits: Array<Record<string, unknown>> }) => ({
total,
hits: hits.filter(
(result: any) => isLabsEnabled || result.type?.stage !== 'experimental'
),
}));
return findListItems(
savedObjects.client,
getTypes(),
searchTerm,
listingLimit,
references
).then(({ total, hits }: { total: number; hits: Array<Record<string, unknown>> }) => ({
total,
hits: hits.filter((result: any) => isLabsEnabled || result.type?.stage !== 'experimental'),
}));
},
[listingLimit, uiSettings, savedObjectsTagging, visualizations]
[listingLimit, uiSettings, savedObjectsTagging, savedObjects.client]
);
const deleteItems = useCallback(
@ -130,7 +133,7 @@ export const VisualizeListing = () => {
selectedItems.map((item: any) => savedObjects.client.delete(item.savedObjectType, item.id))
).catch((error) => {
toastNotifications.addError(error, {
title: i18n.translate('visualize.visualizeListingDeleteErrorTitle', {
title: i18n.translate('visualizations.visualizeListingDeleteErrorTitle', {
defaultMessage: 'Error deleting visualization',
}),
});
@ -148,7 +151,7 @@ export const VisualizeListing = () => {
const calloutMessage = (
<FormattedMessage
data-test-subj="visualize-dashboard-flow-prompt"
id="visualize.visualizeListingDashboardFlowDescription"
id="visualizations.visualizeListingDashboardFlowDescription"
defaultMessage="Building a dashboard? Create and add your visualizations right from the {dashboardApp}."
values={{
dashboardApp: (
@ -160,7 +163,7 @@ export const VisualizeListing = () => {
}}
>
<FormattedMessage
id="visualize.visualizeListingDashboardAppName"
id="visualizations.visualizeListingDashboardAppName"
defaultMessage="Dashboard application"
/>
</EuiLink>
@ -175,7 +178,7 @@ export const VisualizeListing = () => {
// we allow users to create visualizations even if they can't save them
// for data exploration purposes
createItem={createNewVis}
tableCaption={i18n.translate('visualize.listing.table.listTitle', {
tableCaption={i18n.translate('visualizations.listing.table.listTitle', {
defaultMessage: 'Visualize Library',
})}
findItems={fetchItems}
@ -187,25 +190,24 @@ export const VisualizeListing = () => {
initialFilter={''}
rowHeader="title"
emptyPrompt={noItemsFragment}
entityName={i18n.translate('visualize.listing.table.entityName', {
entityName={i18n.translate('visualizations.listing.table.entityName', {
defaultMessage: 'visualization',
})}
entityNamePlural={i18n.translate('visualize.listing.table.entityNamePlural', {
entityNamePlural={i18n.translate('visualizations.listing.table.entityNamePlural', {
defaultMessage: 'visualizations',
})}
tableListTitle={i18n.translate('visualize.listing.table.listTitle', {
tableListTitle={i18n.translate('visualizations.listing.table.listTitle', {
defaultMessage: 'Visualize Library',
})}
toastNotifications={toastNotifications}
searchFilters={searchFilters}
>
{dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables &&
dashboardCapabilities.createNew && (
<>
<EuiCallOut size="s" title={calloutMessage} iconType="iInCircle" />
<EuiSpacer size="m" />
</>
)}
{dashboardCapabilities.createNew && (
<>
<EuiCallOut size="s" title={calloutMessage} iconType="iInCircle" />
<EuiSpacer size="m" />
</>
)}
</TableListView>
);
};

View file

@ -13,7 +13,7 @@ import { EuiCallOut, EuiLink } from '@elastic/eui';
import { useKibana, toMountPoint, KibanaThemeProvider } from '../../../../kibana_react/public';
import { VisualizeServices } from '../types';
import { VisualizeConstants } from '../visualize_constants';
import { VisualizeConstants } from '../../../common/constants';
let bannerId: string;
@ -28,7 +28,7 @@ export const VisualizeNoMatch = () => {
);
if (!navigated) {
const bannerMessage = i18n.translate('visualize.noMatchRoute.bannerTitleText', {
const bannerMessage = i18n.translate('visualizations.noMatchRoute.bannerTitleText', {
defaultMessage: 'Page not found',
});
@ -39,7 +39,7 @@ export const VisualizeNoMatch = () => {
<EuiCallOut color="warning" iconType="iInCircle" title={bannerMessage}>
<p>
<FormattedMessage
id="visualize.noMatchRoute.bannerText"
id="visualizations.noMatchRoute.bannerText"
defaultMessage="Visualize application doesn't recognize this route: {route}."
values={{
route: (

View file

@ -17,7 +17,7 @@ import {
VisualizeAppStateContainer,
VisualizeEditorVisInstance,
} from '../types';
import { APP_NAME } from '../visualize_constants';
import { VISUALIZE_APP_NAME } from '../../../common/constants';
import { getTopNavConfig } from '../utils';
import type { IndexPattern } from '../../../../data/public';
@ -146,10 +146,10 @@ const TopNav = ({
!services.stateTransferService.isTransferInProgress
) {
return actions.confirm(
i18n.translate('visualize.confirmModal.confirmTextDescription', {
i18n.translate('visualizations.confirmModal.confirmTextDescription', {
defaultMessage: 'Leave Visualize editor with unsaved changes?',
}),
i18n.translate('visualize.confirmModal.title', {
i18n.translate('visualizations.confirmModal.title', {
defaultMessage: 'Unsaved changes',
})
);
@ -216,7 +216,7 @@ const TopNav = ({
* it is enabled by default in the TopNavMenu component.
*/
<TopNavMenu
appName={APP_NAME}
appName={VISUALIZE_APP_NAME}
config={config}
setMenuMountPoint={setHeaderActionMenu}
onQuerySubmit={handleRefresh}
@ -238,7 +238,7 @@ const TopNav = ({
* we show the filter bar on its own here if the chrome is not visible.
*/
<TopNavMenu
appName={APP_NAME}
appName={VISUALIZE_APP_NAME}
setMenuMountPoint={setHeaderActionMenu}
indexPatterns={indexPatterns}
showSearchBar

View file

@ -20,7 +20,6 @@ import type {
} from 'kibana/public';
import type {
VisualizationsStart,
Vis,
VisualizeEmbeddableContract,
VisSavedObject,
@ -35,7 +34,7 @@ import type {
} from 'src/plugins/kibana_utils/public';
import type { NavigationPublicPluginStart as NavigationStart } from 'src/plugins/navigation/public';
import { Filter } from '@kbn/es-query';
import type { Filter } from '@kbn/es-query';
import type { Query, DataPublicPluginStart, TimeRange } from 'src/plugins/data/public';
import type { SharePluginStart } from 'src/plugins/share/public';
import type { SavedObjectsStart } from 'src/plugins/saved_objects/public';
@ -43,17 +42,18 @@ import type { EmbeddableStart, EmbeddableStateTransfer } from 'src/plugins/embed
import type { UrlForwardingStart } from 'src/plugins/url_forwarding/public';
import type { PresentationUtilPluginStart } from 'src/plugins/presentation_util/public';
import type { SpacesPluginStart } from '../../../../../x-pack/plugins/spaces/public';
import type { DashboardStart } from '../../../dashboard/public';
import type { SavedObjectsTaggingApi } from '../../../saved_objects_tagging_oss/public';
import type { UsageCollectionStart } from '../../../usage_collection/public';
import type { SavedSearch } from '../../../discover/public';
import { PureVisState } from '../../common/types';
import type { SavedVisState } from '../types';
import type { createVisEmbeddableFromObject } from '../embeddable';
import type { VisEditorsRegistry } from '../vis_editors_registry';
export interface VisualizeAppState {
filters: Filter[];
uiState: SerializableRecord;
vis: PureVisState;
vis: SavedVisState;
query: Query;
savedQuery?: string;
linked: boolean;
@ -66,11 +66,11 @@ export interface VisualizeAppStateTransitions {
prop: T,
value: VisualizeAppState[T]
) => VisualizeAppState;
setVis: (state: VisualizeAppState) => (vis: Partial<PureVisState>) => VisualizeAppState;
setVis: (state: VisualizeAppState) => (vis: Partial<SavedVisState>) => VisualizeAppState;
unlinkSavedSearch: (
state: VisualizeAppState
) => ({ query, parentFilters }: { query?: Query; parentFilters?: Filter[] }) => VisualizeAppState;
updateVisState: (state: VisualizeAppState) => (vis: PureVisState) => VisualizeAppState;
updateVisState: (state: VisualizeAppState) => (vis: SavedVisState) => VisualizeAppState;
updateSavedQuery: (state: VisualizeAppState) => (savedQueryId?: string) => VisualizeAppState;
}
@ -94,19 +94,18 @@ export interface VisualizeServices extends CoreStart {
share?: SharePluginStart;
visualizeCapabilities: Record<string, boolean | Record<string, boolean>>;
dashboardCapabilities: Record<string, boolean | Record<string, boolean>>;
visualizations: VisualizationsStart;
savedObjectsPublic: SavedObjectsStart;
setActiveUrl: (newUrl: string) => void;
createVisEmbeddableFromObject: VisualizationsStart['__LEGACY']['createVisEmbeddableFromObject'];
createVisEmbeddableFromObject: ReturnType<typeof createVisEmbeddableFromObject>;
restorePreviousUrl: () => void;
scopedHistory: ScopedHistory;
dashboard: DashboardStart;
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
savedObjectsTagging?: SavedObjectsTaggingApi;
presentationUtil: PresentationUtilPluginStart;
usageCollection?: UsageCollectionStart;
getKibanaVersion: () => string;
spaces?: SpacesPluginStart;
visEditorsRegistry: VisEditorsRegistry;
}
export interface VisInstance {
@ -145,5 +144,3 @@ export interface EditorRenderProps {
*/
linked: boolean;
}
export type { PureVisState };

View file

@ -8,16 +8,16 @@
import { i18n } from '@kbn/i18n';
import { VisualizeConstants } from '../visualize_constants';
import { VisualizeConstants } from '../../../common/constants';
const defaultEditText = i18n.translate('visualize.editor.defaultEditBreadcrumbText', {
const defaultEditText = i18n.translate('visualizations.editor.defaultEditBreadcrumbText', {
defaultMessage: 'Edit visualization',
});
export function getLandingBreadcrumbs() {
return [
{
text: i18n.translate('visualize.listing.breadcrumb', {
text: i18n.translate('visualizations.listing.breadcrumb', {
defaultMessage: 'Visualize Library',
}),
href: `#${VisualizeConstants.LANDING_PAGE_PATH}`,
@ -38,7 +38,7 @@ export function getCreateBreadcrumbs({
...(originatingAppName ? [{ text: originatingAppName, onClick: redirectToOrigin }] : []),
...(!byValue ? getLandingBreadcrumbs() : []),
{
text: i18n.translate('visualize.editor.createBreadcrumb', {
text: i18n.translate('visualizations.editor.createBreadcrumb', {
defaultMessage: 'Create',
}),
},

View file

@ -14,7 +14,8 @@ import {
syncState,
IKbnUrlStateStorage,
} from '../../../../kibana_utils/public';
import { PureVisState, VisualizeAppState, VisualizeAppStateTransitions } from '../types';
import type { SavedVisState } from '../../types';
import type { VisualizeAppState, VisualizeAppStateTransitions } from '../types';
const STATE_STORAGE_KEY = '_a';
@ -24,10 +25,10 @@ interface Arguments {
byValue?: boolean;
}
function toObject(state: PureVisState): PureVisState {
function toObject(state: SavedVisState): SavedVisState {
return omitBy(state, (value, key: string) => {
return key.charAt(0) === '$' || key.charAt(0) === '_' || isFunction(value);
}) as PureVisState;
}) as SavedVisState;
}
const pureTransitions = {

View file

@ -26,13 +26,13 @@ import type { SavedObjectsTaggingApi } from 'src/plugins/saved_objects_tagging_o
import { RedirectAppLinks } from '../../../../kibana_react/public';
import { getVisualizeListItemLink } from './get_visualize_list_item_link';
import { getUsageCollector } from '../../services';
import { APP_NAME } from '../visualize_constants';
import { VISUALIZE_APP_NAME } from '../../../common/constants';
const doTelemetryForAddEvent = (visType?: string) => {
const usageCollection = getUsageCollector();
if (usageCollection && visType) {
usageCollection.reportUiCounter(APP_NAME, METRIC_TYPE.CLICK, `${visType}:add`);
usageCollection.reportUiCounter(VISUALIZE_APP_NAME, METRIC_TYPE.CLICK, `${visType}:add`);
}
};
@ -42,10 +42,10 @@ const getBadge = (item: VisualizationListItem) => {
<EuiBetaBadge
className="visListingTable__betaIcon"
label="B"
title={i18n.translate('visualize.listing.betaTitle', {
title={i18n.translate('visualizations.listing.betaTitle', {
defaultMessage: 'Beta',
})}
tooltipContent={i18n.translate('visualize.listing.betaTooltip', {
tooltipContent={i18n.translate('visualizations.listing.betaTooltip', {
defaultMessage:
'This visualization is in beta and is subject to change. The design and code is less mature than official GA ' +
'features and is being provided as-is with no warranties. Beta features are not subject to the support SLA of official GA ' +
@ -58,10 +58,10 @@ const getBadge = (item: VisualizationListItem) => {
<EuiBetaBadge
className="visListingTable__experimentalIcon"
label="E"
title={i18n.translate('visualize.listing.experimentalTitle', {
title={i18n.translate('visualizations.listing.experimentalTitle', {
defaultMessage: 'Experimental',
})}
tooltipContent={i18n.translate('visualize.listing.experimentalTooltip', {
tooltipContent={i18n.translate('visualizations.listing.experimentalTooltip', {
defaultMessage:
'This visualization might be changed or removed in a future release and is not subject to the support SLA.',
})}
@ -98,7 +98,7 @@ export const getTableColumns = (
[
{
field: 'title',
name: i18n.translate('visualize.listing.table.titleColumnName', {
name: i18n.translate('visualizations.listing.table.titleColumnName', {
defaultMessage: 'Title',
}),
sortable: true,
@ -123,7 +123,7 @@ export const getTableColumns = (
},
{
field: 'typeTitle',
name: i18n.translate('visualize.listing.table.typeColumnName', {
name: i18n.translate('visualizations.listing.table.typeColumnName', {
defaultMessage: 'Type',
}),
sortable: true,
@ -142,7 +142,7 @@ export const getTableColumns = (
},
{
field: 'description',
name: i18n.translate('visualize.listing.table.descriptionColumnName', {
name: i18n.translate('visualizations.listing.table.descriptionColumnName', {
defaultMessage: 'Description',
}),
sortable: true,
@ -157,7 +157,7 @@ export const getNoItemsMessage = (createItem: () => void) => (
title={
<h1 id="visualizeListingHeading">
<FormattedMessage
id="visualize.listing.createNew.title"
id="visualizations.listing.createNew.title"
defaultMessage="Create your first visualization"
/>
</h1>
@ -165,7 +165,7 @@ export const getNoItemsMessage = (createItem: () => void) => (
body={
<p>
<FormattedMessage
id="visualize.listing.createNew.description"
id="visualizations.listing.createNew.description"
defaultMessage="You can create different visualizations based on your data."
/>
</p>
@ -178,7 +178,7 @@ export const getNoItemsMessage = (createItem: () => void) => (
data-test-subj="createVisualizationPromptButton"
>
<FormattedMessage
id="visualize.listing.createNew.createButtonLabel"
id="visualizations.listing.createNew.createButtonLabel"
defaultMessage="Create new visualization"
/>
</EuiButton>

View file

@ -73,11 +73,6 @@ describe('getTopNavConfig', () => {
const share = sharePluginMock.createStartContract();
const services = {
...mockServices,
dashboard: {
dashboardFeatureFlagConfig: {
allowByValueEmbeddables: true,
},
},
visualizeCapabilities: {
save: true,
},

View file

@ -14,6 +14,7 @@ import { parse } from 'query-string';
import { Capabilities } from 'src/core/public';
import { TopNavMenuData } from 'src/plugins/navigation/public';
import { saveVisualization } from '../../utils/saved_visualize_utils';
import {
VISUALIZE_EMBEDDABLE_TYPE,
VisualizeInput,
@ -36,7 +37,7 @@ import {
VisualizeAppStateContainer,
VisualizeEditorVisInstance,
} from '../types';
import { APP_NAME, VisualizeConstants } from '../visualize_constants';
import { VISUALIZE_APP_NAME, VisualizeConstants } from '../../../common/constants';
import { getEditBreadcrumbs } from './breadcrumbs';
import { EmbeddableStateTransfer } from '../../../../embeddable/public';
import { VISUALIZE_APP_LOCATOR, VisualizeLocatorParams } from '../../../common/locator';
@ -101,13 +102,11 @@ export const getTopNavConfig = (
visualizeCapabilities,
dashboardCapabilities,
i18n: { Context: I18nContext },
dashboard,
savedObjectsTagging,
presentationUtil,
usageCollection,
getKibanaVersion,
savedObjects,
visualizations,
}: VisualizeServices
) => {
const { vis, embeddableHandler } = visInstance;
@ -116,7 +115,7 @@ export const getTopNavConfig = (
const doTelemetryForSaveEvent = (visType: string) => {
if (usageCollection) {
usageCollection.reportUiCounter(
originatingApp ?? APP_NAME,
originatingApp ?? VISUALIZE_APP_NAME,
METRIC_TYPE.CLICK,
`${visType}:save`
);
@ -140,16 +139,23 @@ export const getTopNavConfig = (
setHasUnsavedChanges(false);
try {
const id = await visualizations.saveVisualization(savedVis, saveOptions);
const id = await saveVisualization(savedVis, saveOptions, {
savedObjectsClient: savedObjects.client,
overlays,
savedObjectsTagging,
});
if (id) {
toastNotifications.addSuccess({
title: i18n.translate('visualize.topNavMenu.saveVisualization.successNotificationText', {
defaultMessage: `Saved '{visTitle}'`,
values: {
visTitle: savedVis.title,
},
}),
title: i18n.translate(
'visualizations.topNavMenu.saveVisualization.successNotificationText',
{
defaultMessage: `Saved '{visTitle}'`,
values: {
visTitle: savedVis.title,
},
}
),
'data-test-subj': 'saveVisualizationSuccess',
});
@ -210,12 +216,15 @@ export const getTopNavConfig = (
// eslint-disable-next-line
console.error(error);
toastNotifications.addDanger({
title: i18n.translate('visualize.topNavMenu.saveVisualization.failureNotificationText', {
defaultMessage: `Error on saving '{visTitle}'`,
values: {
visTitle: savedVis.title,
},
}),
title: i18n.translate(
'visualizations.topNavMenu.saveVisualization.failureNotificationText',
{
defaultMessage: `Error on saving '{visTitle}'`,
values: {
visTitle: savedVis.title,
},
}
),
text: error.message,
'data-test-subj': 'saveVisualizationError',
});
@ -246,32 +255,29 @@ export const getTopNavConfig = (
}
};
const allowByValue = dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables;
const saveButtonLabel =
!savedVis.id && allowByValue && originatingApp
? i18n.translate('visualize.topNavMenu.saveVisualizationToLibraryButtonLabel', {
!savedVis.id && originatingApp
? i18n.translate('visualizations.topNavMenu.saveVisualizationToLibraryButtonLabel', {
defaultMessage: 'Save to library',
})
: originatingApp && savedVis.id
? i18n.translate('visualize.topNavMenu.saveVisualizationAsButtonLabel', {
? i18n.translate('visualizations.topNavMenu.saveVisualizationAsButtonLabel', {
defaultMessage: 'Save as',
})
: i18n.translate('visualize.topNavMenu.saveVisualizationButtonLabel', {
: i18n.translate('visualizations.topNavMenu.saveVisualizationButtonLabel', {
defaultMessage: 'Save',
});
const showSaveAndReturn = originatingApp && (savedVis?.id || allowByValue);
const showSaveButton =
visualizeCapabilities.save ||
(allowByValue && !showSaveAndReturn && dashboardCapabilities.showWriteControls);
visualizeCapabilities.save || (!originatingApp && dashboardCapabilities.showWriteControls);
const topNavMenu: TopNavMenuData[] = [
{
id: 'inspector',
label: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', {
label: i18n.translate('visualizations.topNavMenu.openInspectorButtonLabel', {
defaultMessage: 'inspect',
}),
description: i18n.translate('visualize.topNavMenu.openInspectorButtonAriaLabel', {
description: i18n.translate('visualizations.topNavMenu.openInspectorButtonAriaLabel', {
defaultMessage: 'Open Inspector for visualization',
}),
testId: 'openInspectorButton',
@ -281,7 +287,7 @@ export const getTopNavConfig = (
run: openInspector,
tooltip() {
if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) {
return i18n.translate('visualize.topNavMenu.openInspectorDisabledButtonTooltip', {
return i18n.translate('visualizations.topNavMenu.openInspectorDisabledButtonTooltip', {
defaultMessage: `This visualization doesn't support any inspectors.`,
});
}
@ -289,10 +295,10 @@ export const getTopNavConfig = (
},
{
id: 'share',
label: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', {
label: i18n.translate('visualizations.topNavMenu.shareVisualizationButtonLabel', {
defaultMessage: 'share',
}),
description: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', {
description: i18n.translate('visualizations.topNavMenu.shareVisualizationButtonAriaLabel', {
defaultMessage: 'Share Visualization',
}),
testId: 'shareTopNavButton',
@ -325,7 +331,7 @@ export const getTopNavConfig = (
sharingData: {
title:
savedVis?.title ||
i18n.translate('visualize.reporting.defaultReportTitle', {
i18n.translate('visualizations.reporting.defaultReportTitle', {
defaultMessage: 'Visualization [{date}]',
values: { date: moment().toISOString(true) },
}),
@ -341,23 +347,23 @@ export const getTopNavConfig = (
}
},
// disable the Share button if no action specified and fot byValue visualizations
disableButton: !share || Boolean(!savedVis.id && allowByValue && originatingApp),
disableButton: !share || Boolean(!savedVis.id && originatingApp),
},
...(originatingApp
? [
{
id: 'cancel',
label: i18n.translate('visualize.topNavMenu.cancelButtonLabel', {
label: i18n.translate('visualizations.topNavMenu.cancelButtonLabel', {
defaultMessage: 'Cancel',
}),
emphasize: false,
description: i18n.translate('visualize.topNavMenu.cancelButtonAriaLabel', {
description: i18n.translate('visualizations.topNavMenu.cancelButtonAriaLabel', {
defaultMessage: 'Return to the last app without saving changes',
}),
testId: 'visualizeCancelAndReturnButton',
tooltip() {
if (hasUnappliedChanges || hasUnsavedChanges) {
return i18n.translate('visualize.topNavMenu.cancelAndReturnButtonTooltip', {
return i18n.translate('visualizations.topNavMenu.cancelAndReturnButtonTooltip', {
defaultMessage: 'Discard your changes before finishing',
});
}
@ -372,18 +378,21 @@ export const getTopNavConfig = (
? [
{
id: 'save',
iconType: showSaveAndReturn ? undefined : 'save',
iconType: originatingApp ? undefined : 'save',
label: saveButtonLabel,
emphasize: !showSaveAndReturn,
description: i18n.translate('visualize.topNavMenu.saveVisualizationButtonAriaLabel', {
defaultMessage: 'Save Visualization',
}),
emphasize: !originatingApp,
description: i18n.translate(
'visualizations.topNavMenu.saveVisualizationButtonAriaLabel',
{
defaultMessage: 'Save Visualization',
}
),
testId: 'visualizeSaveButton',
disableButton: hasUnappliedChanges,
tooltip() {
if (hasUnappliedChanges) {
return i18n.translate(
'visualize.topNavMenu.saveVisualizationDisabledButtonTooltip',
'visualizations.topNavMenu.saveVisualizationDisabledButtonTooltip',
{
defaultMessage: 'Apply or Discard your changes before saving',
}
@ -483,26 +492,26 @@ export const getTopNavConfig = (
);
}
const useByRefFlow =
!!originatingApp || !dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables;
let saveModal;
if (useByRefFlow) {
if (originatingApp) {
saveModal = (
<SavedObjectSaveModalOrigin
documentInfo={savedVis || { title: '' }}
onSave={onSave}
options={tagOptions}
getAppNameFromId={stateTransfer.getAppNameFromId}
objectType={i18n.translate('visualize.topNavMenu.saveVisualizationObjectType', {
defaultMessage: 'visualization',
})}
objectType={i18n.translate(
'visualizations.topNavMenu.saveVisualizationObjectType',
{
defaultMessage: 'visualization',
}
)}
onClose={() => {}}
originatingApp={originatingApp}
returnToOriginSwitchLabel={
originatingApp && embeddableId
? i18n.translate('visualize.topNavMenu.updatePanel', {
? i18n.translate('visualizations.topNavMenu.updatePanel', {
defaultMessage: 'Update panel on {originatingAppName}',
values: {
originatingAppName: stateTransfer.getAppNameFromId(originatingApp),
@ -523,9 +532,12 @@ export const getTopNavConfig = (
canSaveByReference={Boolean(visualizeCapabilities.save)}
onSave={onSave}
tagOptions={tagOptions}
objectType={i18n.translate('visualize.topNavMenu.saveVisualizationObjectType', {
defaultMessage: 'visualization',
})}
objectType={i18n.translate(
'visualizations.topNavMenu.saveVisualizationObjectType',
{
defaultMessage: 'visualization',
}
)}
onClose={() => {}}
/>
);
@ -534,23 +546,26 @@ export const getTopNavConfig = (
showSaveModal(
saveModal,
I18nContext,
!useByRefFlow ? presentationUtil.ContextProvider : React.Fragment
!originatingApp ? presentationUtil.ContextProvider : React.Fragment
);
},
},
]
: []),
...(showSaveAndReturn
...(originatingApp
? [
{
id: 'saveAndReturn',
label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', {
defaultMessage: 'Save and return',
}),
label: i18n.translate(
'visualizations.topNavMenu.saveAndReturnVisualizationButtonLabel',
{
defaultMessage: 'Save and return',
}
),
emphasize: true,
iconType: 'checkInCircleFilled',
description: i18n.translate(
'visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel',
'visualizations.topNavMenu.saveAndReturnVisualizationButtonAriaLabel',
{
defaultMessage: 'Finish editing visualization and return to the last app',
}
@ -560,7 +575,7 @@ export const getTopNavConfig = (
tooltip() {
if (hasUnappliedChanges) {
return i18n.translate(
'visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip',
'visualizations.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip',
{
defaultMessage: 'Apply or Discard your changes before finishing',
}

View file

@ -18,8 +18,30 @@ import {
getVisualizationInstanceFromInput,
} from './get_visualization_instance';
import { createVisualizeServicesMock } from './mocks';
import { VisualizeServices } from '../types';
import { BehaviorSubject } from 'rxjs';
import type { VisualizeServices } from '../types';
const commonSerializedVisMock = {
type: 'area',
aggs: [],
};
jest.mock('../../utils/saved_visualize_utils', () => {
const actual = jest.requireActual('../../utils/saved_visualize_utils');
return {
...actual,
getSavedVisualization: jest.fn(),
convertToSerializedVis: jest.fn().mockReturnValue(commonSerializedVisMock),
};
});
const { getSavedVisualization, convertToSerializedVis } = jest.requireMock(
'../../utils/saved_visualize_utils'
);
jest.mock('../../vis_async', () => ({
createVisAsync: jest.fn(),
}));
const { createVisAsync } = jest.requireMock('../../vis_async');
jest.mock('../../../../discover/public', () => ({
getSavedSearch: jest.fn().mockResolvedValue({
@ -33,9 +55,6 @@ jest.mock('../../../../discover/public', () => ({
let savedVisMock: VisSavedObject;
describe('getVisualizationInstance', () => {
const serializedVisMock = {
type: 'area',
};
let visMock: Vis<VisParams>;
let mockServices: jest.Mocked<VisualizeServices>;
let subj: BehaviorSubject<any>;
@ -49,18 +68,10 @@ describe('getVisualizationInstance', () => {
} as Vis<VisParams>;
savedVisMock = {} as VisSavedObject;
// @ts-expect-error
mockServices.data.search.showError.mockImplementation(() => {});
// @ts-expect-error
mockServices.visualizations.convertToSerializedVis.mockImplementation(() => serializedVisMock);
// @ts-expect-error
mockServices.visualizations.getSavedVisualization.mockImplementation(
(opts: unknown) => savedVisMock
);
// @ts-expect-error
mockServices.visualizations.createVis.mockImplementation(() => visMock);
// @ts-expect-error
mockServices.createVisEmbeddableFromObject.mockImplementation(() => ({
getSavedVisualization.mockImplementation((opts: unknown) => savedVisMock);
createVisAsync.mockImplementation(() => visMock);
mockServices.data.search.showError = jest.fn().mockImplementation(() => {});
mockServices.createVisEmbeddableFromObject = jest.fn().mockImplementation(() => ({
getOutput$: jest.fn(() => subj.asObservable()),
}));
});
@ -75,16 +86,14 @@ describe('getVisualizationInstance', () => {
opts
);
expect((mockServices.visualizations.getSavedVisualization as jest.Mock).mock.calls[0][0]).toBe(
opts
);
expect(getSavedVisualization.mock.calls[0][1]).toBe(opts);
expect(savedVisMock.searchSourceFields).toEqual({
index: opts.indexPattern,
});
expect(mockServices.visualizations.convertToSerializedVis).toHaveBeenCalledWith(savedVisMock);
expect(mockServices.visualizations.createVis).toHaveBeenCalledWith(
serializedVisMock.type,
serializedVisMock
expect(convertToSerializedVis).toHaveBeenCalledWith(savedVisMock);
expect(createVisAsync).toHaveBeenCalledWith(
commonSerializedVisMock.type,
commonSerializedVisMock
);
expect(mockServices.createVisEmbeddableFromObject).toHaveBeenCalledWith(visMock, {
searchSessionId: undefined,
@ -106,9 +115,7 @@ describe('getVisualizationInstance', () => {
visMock.type.setup = jest.fn(() => newVisObj);
const { vis } = await getVisualizationInstance(mockServices, 'saved_vis_id');
expect((mockServices.visualizations.getSavedVisualization as jest.Mock).mock.calls[0][0]).toBe(
'saved_vis_id'
);
expect(getSavedVisualization.mock.calls[1][1]).toBe('saved_vis_id');
expect(savedVisMock.searchSourceFields).toBeUndefined();
expect(visMock.type.setup).toHaveBeenCalledWith(visMock);
expect(vis).toBe(newVisObj);
@ -155,14 +162,10 @@ describe('getVisualizationInstanceInput', () => {
data: {},
} as Vis<VisParams>;
savedVisMock = {} as VisSavedObject;
// @ts-expect-error
mockServices.visualizations.createVis.mockImplementation(() => visMock);
// @ts-expect-error
mockServices.visualizations.getSavedVisualization.mockImplementation(
(opts: unknown) => savedVisMock
);
// @ts-expect-error
mockServices.createVisEmbeddableFromObject.mockImplementation(() => ({
createVisAsync.mockImplementation(() => visMock);
getSavedVisualization.mockImplementation((opts: unknown) => savedVisMock);
mockServices.createVisEmbeddableFromObject = jest.fn().mockImplementation(() => ({
getOutput$: jest.fn(() => subj.asObservable()),
}));
});
@ -199,11 +202,8 @@ describe('getVisualizationInstanceInput', () => {
const { savedVis, savedSearch, vis, embeddableHandler } =
await getVisualizationInstanceFromInput(mockServices, input);
expect(mockServices.visualizations.getSavedVisualization).toHaveBeenCalled();
expect(mockServices.visualizations.createVis).toHaveBeenCalledWith(
serializedVisMock.type,
input.savedVis
);
expect(getSavedVisualization).toHaveBeenCalled();
expect(createVisAsync).toHaveBeenCalledWith(serializedVisMock.type, input.savedVis);
expect(mockServices.createVisEmbeddableFromObject).toHaveBeenCalledWith(visMock, {
searchSessionId: undefined,
timeRange: undefined,

View file

@ -13,16 +13,18 @@ import {
VisualizeEmbeddableContract,
VisualizeInput,
} from 'src/plugins/visualizations/public';
import { SerializedSearchSourceFields } from 'src/plugins/data/public';
import { cloneDeep } from 'lodash';
import { ExpressionValueError } from 'src/plugins/expressions/public';
import type { SerializedSearchSourceFields } from 'src/plugins/data/public';
import type { ExpressionValueError } from 'src/plugins/expressions/public';
import { createVisAsync } from '../../vis_async';
import { convertToSerializedVis, getSavedVisualization } from '../../utils/saved_visualize_utils';
import { SavedFieldNotFound, SavedFieldTypeInvalidForAgg } from '../../../../kibana_utils/common';
import {
getSavedSearch,
SavedSearch,
throwErrorOnSavedSearchUrlConflict,
} from '../../../../discover/public';
import { SavedFieldNotFound, SavedFieldTypeInvalidForAgg } from '../../../../kibana_utils/common';
import { VisualizeServices } from '../types';
import type { VisualizeServices } from '../types';
function isErrorRelatedToRuntimeFields(error: ExpressionValueError['error']) {
const originalError = error.original || error;
@ -72,20 +74,26 @@ export const getVisualizationInstanceFromInput = async (
visualizeServices: VisualizeServices,
input: VisualizeInput
) => {
const { visualizations } = visualizeServices;
const { data, savedObjects, spaces, savedObjectsTagging } = visualizeServices;
const visState = input.savedVis as SerializedVis;
/**
* A saved vis is needed even in by value mode to support 'save to library' which converts the 'by value'
* state of the visualization, into a new saved object.
*/
const savedVis: VisSavedObject = await visualizations.getSavedVisualization();
const savedVis: VisSavedObject = await getSavedVisualization({
search: data.search,
savedObjectsClient: savedObjects.client,
dataViews: data.dataViews,
spaces,
savedObjectsTagging,
});
if (visState.uiState && Object.keys(visState.uiState).length !== 0) {
savedVis.uiStateJSON = JSON.stringify(visState.uiState);
}
let vis = await visualizations.createVis(visState.type, cloneDeep(visState));
let vis = await createVisAsync(visState.type, cloneDeep(visState));
if (vis.type.setup) {
try {
vis = await vis.type.setup(vis);
@ -114,14 +122,24 @@ export const getVisualizationInstance = async (
*/
opts?: Record<string, unknown> | string
) => {
const { visualizations } = visualizeServices;
const savedVis: VisSavedObject = await visualizations.getSavedVisualization(opts);
const { data, savedObjects, spaces, savedObjectsTagging } = visualizeServices;
const savedVis: VisSavedObject = await getSavedVisualization(
{
search: data.search,
savedObjectsClient: savedObjects.client,
dataViews: data.dataViews,
spaces,
savedObjectsTagging,
},
opts
);
if (typeof opts !== 'string') {
savedVis.searchSourceFields = { index: opts?.indexPattern } as SerializedSearchSourceFields;
}
const serializedVis = visualizations.convertToSerializedVis(savedVis);
let vis = await visualizations.createVis(serializedVis.type, serializedVis);
const serializedVis = convertToSerializedVis(savedVis);
let vis = await createVisAsync(serializedVis.type, serializedVis);
if (vis.type.setup) {
try {
vis = await vis.type.setup(vis);

View file

@ -11,8 +11,7 @@ import { IKbnUrlStateStorage } from 'src/plugins/kibana_utils/public';
import { QueryState } from '../../../../data/public';
import { setStateToKbnUrl } from '../../../../kibana_utils/public';
import { getUISettings } from '../../services';
import { GLOBAL_STATE_STORAGE_KEY } from '../../../common/constants';
import { APP_NAME } from '../visualize_constants';
import { GLOBAL_STATE_STORAGE_KEY, VISUALIZE_APP_NAME } from '../../../common/constants';
export const getVisualizeListItemLink = (
application: ApplicationStart,
@ -21,7 +20,7 @@ export const getVisualizeListItemLink = (
editUrl: string
) => {
// for visualizations the editApp is undefined
let url = application.getUrlForApp(editApp ?? APP_NAME, {
let url = application.getUrlForApp(editApp ?? VISUALIZE_APP_NAME, {
path: editApp ? editUrl : `#${editUrl}`,
});
const useHash = getUISettings().get('state:storeInSessionStorage');

View file

@ -8,14 +8,12 @@
import { coreMock } from '../../../../../core/public/mocks';
import { dataPluginMock } from '../../../../data/public/mocks';
import { visualizationsPluginMock } from '../../../../visualizations/public/mocks';
import { VisualizeServices } from '../types';
export const createVisualizeServicesMock = () => {
const coreStartMock = coreMock.createStart();
const dataStartMock = dataPluginMock.createStartContract();
const toastNotifications = coreStartMock.notifications.toasts;
const visualizations = visualizationsPluginMock.createStartContract();
return {
...coreStartMock,
@ -25,7 +23,5 @@ export const createVisualizeServicesMock = () => {
replace: jest.fn(),
location: { pathname: '' },
},
visualizations,
createVisEmbeddableFromObject: visualizations.__LEGACY.createVisEmbeddableFromObject,
} as unknown as jest.Mocked<VisualizeServices>;
};

View file

@ -15,6 +15,11 @@ import type { IEditorController } from '../../types';
import { visualizeAppStateStub } from '../stubs';
import { createVisualizeServicesMock } from '../mocks';
jest.mock('../../../utils/saved_visualize_utils', () => {
const stubs = jest.requireActual('../stubs');
return { convertFromSerializedVis: () => ({ visState: stubs.visualizeAppStateStub.vis }) };
});
describe('useEditorUpdates', () => {
const eventEmitter = new EventEmitter();
const setHasUnsavedChangesMock = jest.fn();
@ -22,10 +27,6 @@ describe('useEditorUpdates', () => {
beforeEach(() => {
mockServices = createVisualizeServicesMock();
// @ts-expect-error
mockServices.visualizations.convertFromSerializedVis.mockImplementation(() => ({
visState: visualizeAppStateStub.vis,
}));
});
test('should not create any subscriptions if app state container is not ready', () => {

View file

@ -17,6 +17,7 @@ import {
VisualizeEditorVisInstance,
IEditorController,
} from '../../types';
import { convertFromSerializedVis } from '../../../utils/saved_visualize_utils';
export const useEditorUpdates = (
services: VisualizeServices,
@ -113,7 +114,7 @@ export const useEditorUpdates = (
savedVis &&
!isEqual(
{
...services.visualizations.convertFromSerializedVis(vis.serialize()).visState,
...convertFromSerializedVis(vis.serialize()).visState,
title: vis.title,
},
state.vis

View file

@ -43,7 +43,7 @@ export const useLinkedSearchUpdates = (
});
services.toastNotifications.addSuccess(
i18n.translate('visualize.linkedToSearch.unlinkSuccessNotificationText', {
i18n.translate('visualizations.linkedToSearch.unlinkSuccessNotificationText', {
defaultMessage: `Unlinked from saved search '{searchTitle}'`,
values: {
searchTitle: savedSearch.title,

View file

@ -9,15 +9,16 @@
import { renderHook } from '@testing-library/react-hooks';
import { EventEmitter } from 'events';
import { setTypes } from '../../../services';
import { coreMock } from '../../../../../../core/public/mocks';
import { useSavedVisInstance } from './use_saved_vis_instance';
import { redirectWhenMissing } from '../../../../../kibana_utils/public';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { VisualizeServices } from '../../types';
import { VisualizeConstants } from '../../visualize_constants';
import { setVisEditorsRegistry } from '../../../services';
import { VisualizeConstants } from '../../../../common/constants';
import { createVisEditorsRegistry } from '../../../vis_editors_registry';
import { createEmbeddableStateTransferMock } from '../../../../../embeddable/public/mocks';
import type { VisualizeServices } from '../../types';
import type { TypesStart } from '../../../vis_types';
const mockDefaultEditorControllerDestroy = jest.fn();
const mockEmbeddableHandlerDestroy = jest.fn();
@ -40,6 +41,10 @@ const mockSavedVisInstance = {
jest.mock('../get_visualization_instance', () => ({
getVisualizationInstance: jest.fn(() => mockSavedVisInstance),
}));
const mockGetVisualizationInstance = jest.requireMock(
'../get_visualization_instance'
).getVisualizationInstance;
jest.mock('../breadcrumbs', () => ({
getEditBreadcrumbs: jest.fn((args, title) => title),
getCreateBreadcrumbs: jest.fn((text) => text),
@ -53,28 +58,33 @@ jest.mock('../../../../../kibana_utils/public', () => {
};
});
const mockGetVisualizationInstance = jest.requireMock(
'../get_visualization_instance'
).getVisualizationInstance;
describe('useSavedVisInstance', () => {
const coreStartMock = coreMock.createStart();
const toastNotifications = coreStartMock.notifications.toasts;
let mockServices: VisualizeServices;
const eventEmitter = new EventEmitter();
beforeEach(() => {
const registry = createVisEditorsRegistry();
beforeAll(() => {
setTypes({
all: jest
.fn()
.mockReturnValue([
{ name: 'area', requiresSearch: true, options: { showIndexSelection: true } },
]),
} as unknown as TypesStart);
});
registry.registerDefault(
beforeEach(() => {
const visEditorsRegistry = createVisEditorsRegistry();
visEditorsRegistry.registerDefault(
jest.fn().mockImplementation(() => ({ destroy: mockDefaultEditorControllerDestroy }))
);
setVisEditorsRegistry(registry);
mockServices = {
...coreStartMock,
toastNotifications,
visEditorsRegistry,
stateTransferService: createEmbeddableStateTransferMock(),
chrome: { setBreadcrumbs: jest.fn(), docTitle: { change: jest.fn() } },
history: {
@ -83,7 +93,6 @@ describe('useSavedVisInstance', () => {
},
replace: () => {},
},
dashboard: { dashboardFeatureFlagConfig: { allowByValueEmbeddables: false } },
visualizations: {
all: jest.fn(() => [
{

View file

@ -14,8 +14,8 @@ import { i18n } from '@kbn/i18n';
import { getVisualizationInstance } from '../get_visualization_instance';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { SavedVisInstance, VisualizeServices, IEditorController } from '../../types';
import { VisualizeConstants } from '../../visualize_constants';
import { getVisEditorsRegistry } from '../../../services';
import { VisualizeConstants } from '../../../../common/constants';
import { getTypes } from '../../../services';
import { redirectToSavedObjectPage } from '../utils';
/**
@ -41,9 +41,9 @@ export const useSavedVisInstance = (
const {
chrome,
history,
dashboard,
toastNotifications,
stateTransferService,
visEditorsRegistry,
application: { navigateToApp },
} = services;
const getSavedVisInstance = async () => {
@ -51,12 +51,13 @@ export const useSavedVisInstance = (
let savedVisInstance: SavedVisInstance;
if (history.location.pathname === '/create') {
const searchParams = parse(history.location.search);
const visTypes = services.visualizations.all();
const visType = visTypes.find(({ name }) => name === searchParams.type);
const visType = getTypes()
.all()
.find(({ name }) => name === searchParams.type);
if (!visType) {
throw new Error(
i18n.translate('visualize.createVisualization.noVisTypeErrorMessage', {
i18n.translate('visualizations.createVisualization.noVisTypeErrorMessage', {
defaultMessage: 'You must provide a valid visualization type',
})
);
@ -68,7 +69,7 @@ export const useSavedVisInstance = (
if (shouldHaveIndex && !hasIndex) {
throw new Error(
i18n.translate(
'visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage',
'visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage',
{
defaultMessage: 'You must provide either an indexPattern or a savedSearchId',
}
@ -87,8 +88,6 @@ export const useSavedVisInstance = (
? stateTransferService.getAppNameFromId(originatingApp)
: undefined;
const redirectToOrigin = originatingApp ? () => navigateToApp(originatingApp) : undefined;
const byValueCreateMode =
Boolean(originatingApp) && dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables;
if (savedVis.id) {
chrome.setBreadcrumbs(
@ -98,7 +97,7 @@ export const useSavedVisInstance = (
} else {
chrome.setBreadcrumbs(
getCreateBreadcrumbs({
byValue: byValueCreateMode,
byValue: Boolean(originatingApp),
originatingAppName,
redirectToOrigin,
})
@ -109,7 +108,7 @@ export const useSavedVisInstance = (
// do not create editor in embeded mode
if (visEditorRef.current) {
if (isChromeVisible) {
const Editor = getVisEditorsRegistry().get(vis.type.editorConfig?.editor);
const Editor = visEditorsRegistry.get(vis.type.editorConfig?.editor);
if (Editor) {
visEditorController = new Editor(
@ -132,7 +131,7 @@ export const useSavedVisInstance = (
redirectToSavedObjectPage(services, error, visualizationIdFromUrl);
} catch (e) {
toastNotifications.addWarning({
title: i18n.translate('visualize.createVisualization.failedToLoadErrorMessage', {
title: i18n.translate('visualizations.createVisualization.failedToLoadErrorMessage', {
defaultMessage: 'Failed to load the visualization',
}),
text: e.message,

View file

@ -12,7 +12,6 @@ import { VisualizeInput } from 'src/plugins/visualizations/public';
import { ByValueVisInstance, VisualizeServices, IEditorController } from '../../types';
import { getVisualizationInstanceFromInput } from '../get_visualization_instance';
import { getEditBreadcrumbs } from '../breadcrumbs';
import { getVisEditorsRegistry } from '../../../services';
export const useVisByValue = (
services: VisualizeServices,
@ -33,6 +32,7 @@ export const useVisByValue = (
chrome,
application: { navigateToApp },
stateTransferService,
visEditorsRegistry,
} = services;
const getVisInstance = async () => {
if (!valueInput || loaded.current || !visEditorRef.current) {
@ -42,7 +42,7 @@ export const useVisByValue = (
const { embeddableHandler, vis } = byValueVisInstance;
let visEditorController;
const Editor = getVisEditorsRegistry().get(vis.type.editorConfig?.editor);
const Editor = visEditorsRegistry.get(vis.type.editorConfig?.editor);
if (Editor) {
visEditorController = new Editor(

View file

@ -13,7 +13,7 @@ import { Observable } from 'rxjs';
import { useVisualizeAppState } from './use_visualize_app_state';
import { VisualizeServices, SavedVisInstance } from '../../types';
import { visualizeAppStateStub } from '../stubs';
import { VisualizeConstants } from '../../visualize_constants';
import { VisualizeConstants } from '../../../../common/constants';
import { createVisualizeServicesMock } from '../mocks';
jest.mock('../utils');

View file

@ -26,7 +26,7 @@ import {
} from '../../types';
import { visStateToEditorState } from '../utils';
import { createVisualizeAppState } from '../create_visualize_app_state';
import { VisualizeConstants } from '../../visualize_constants';
import { VisualizeConstants } from '../../../../common/constants';
/**
* This effect is responsible for instantiating the visualize app state container,
* which is in sync with "_a" url param
@ -126,7 +126,7 @@ export const useVisualizeAppState = (
// if setting new vis state was failed for any reason,
// redirect to the listing page with error message
services.toastNotifications.addWarning({
title: i18n.translate('visualize.visualizationLoadingFailedErrorMessage', {
title: i18n.translate('visualizations.visualizationLoadingFailedErrorMessage', {
defaultMessage: 'Failed to load the visualization',
}),
text: toMountPoint(

View file

@ -8,15 +8,16 @@
import { i18n } from '@kbn/i18n';
import { ChromeStart, DocLinksStart } from 'kibana/public';
import { Filter } from '@kbn/es-query';
import type { ChromeStart, DocLinksStart } from 'kibana/public';
import type { Filter } from '@kbn/es-query';
import { redirectWhenMissing } from '../../../../kibana_utils/public';
import { VisualizeConstants } from '../visualize_constants';
import { VisualizeServices, VisualizeEditorVisInstance } from '../types';
import { VisualizeConstants } from '../../../common/constants';
import { convertFromSerializedVis } from '../../utils/saved_visualize_utils';
import type { VisualizeServices, VisualizeEditorVisInstance } from '../types';
export const addHelpMenuToAppChrome = (chrome: ChromeStart, docLinks: DocLinksStart) => {
chrome.setHelpExtension({
appName: i18n.translate('visualize.helpMenu.appName', {
appName: i18n.translate('visualizations.helpMenu.appName', {
defaultMessage: 'Visualize Library',
}),
links: [
@ -30,10 +31,10 @@ export const addHelpMenuToAppChrome = (chrome: ChromeStart, docLinks: DocLinksSt
export const addBadgeToAppChrome = (chrome: ChromeStart) => {
chrome.setBadge({
text: i18n.translate('visualize.badge.readOnly.text', {
text: i18n.translate('visualizations.badge.readOnly.text', {
defaultMessage: 'Read only',
}),
tooltip: i18n.translate('visualize.badge.readOnly.tooltip', {
tooltip: i18n.translate('visualizations.badge.readOnly.tooltip', {
defaultMessage: 'Unable to save visualizations to the library',
}),
iconType: 'glasses',
@ -49,7 +50,7 @@ export const visStateToEditorState = (
services: VisualizeServices
) => {
const vis = visInstance.vis;
const savedVisState = services.visualizations.convertFromSerializedVis(vis.serialize());
const savedVisState = convertFromSerializedVis(vis.serialize());
const savedVis = 'savedVis' in visInstance ? visInstance.savedVis : undefined;
return {
uiState:

View file

@ -12,6 +12,7 @@ import { schema } from '@kbn/config-schema';
import { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants';
import { visualizationSavedObjectType } from './saved_objects';
import { registerVisualizationsCollector } from './usage_collector';
import { capabilitiesProvider } from './capabilities_provider';
import type { VisualizationsPluginSetup, VisualizationsPluginStart } from './types';
import type {
@ -41,6 +42,7 @@ export class VisualizationsPlugin
this.logger.debug('visualizations: Setup');
core.savedObjects.registerType(visualizationSavedObjectType);
core.capabilities.registerProvider(capabilitiesProvider);
core.uiSettings.register({
[VISUALIZE_ENABLE_LABS_SETTING]: {

View file

@ -9,7 +9,8 @@
"include": [
"common/**/*",
"public/**/*",
"server/**/*"
"server/**/*",
"../../../typings/**/*"
],
"references": [
{ "path": "../../core/tsconfig.json" },
@ -22,7 +23,13 @@
{ "path": "../saved_objects_tagging_oss/tsconfig.json" },
{ "path": "../usage_collection/tsconfig.json" },
{ "path": "../kibana_utils/tsconfig.json" },
{ "path": "../kibana_react/tsconfig.json" },
{ "path": "../discover/tsconfig.json" },
{ "path": "../../../x-pack/plugins/spaces/tsconfig.json" },
{ "path": "../url_forwarding/tsconfig.json" },
{ "path": "../navigation/tsconfig.json" },
{ "path": "../home/tsconfig.json" },
{ "path": "../share/tsconfig.json" },
{ "path": "../presentation_util/tsconfig.json" },
{ "path": "../../../x-pack/plugins/spaces/tsconfig.json" }
]
}

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export const STATE_STORAGE_KEY = '_a';
export const GLOBAL_STATE_STORAGE_KEY = '_g';
export const APP_NAME = 'visualize';
export const VisualizeConstants = {
VISUALIZE_BASE_PATH: '/app/visualize',
LANDING_PAGE_PATH: '/',
WIZARD_STEP_1_PAGE_PATH: '/new',
WIZARD_STEP_2_PAGE_PATH: '/new/configure',
CREATE_PATH: '/create',
EDIT_PATH: '/edit',
EDIT_BY_VALUE_PATH: '/edit_by_value',
APP_ID: 'visualize',
};

View file

@ -1,10 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { SavedVisState } from 'src/plugins/visualizations/common/types';
export type PureVisState = SavedVisState;

View file

@ -1,16 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../..',
roots: ['<rootDir>/src/plugins/visualize'],
coverageDirectory: '<rootDir>/target/kibana-coverage/jest/src/plugins/visualize',
coverageReporters: ['text', 'html'],
collectCoverageFrom: ['<rootDir>/src/plugins/visualize/{common,public,server}/**/*.{ts,tsx}'],
};

View file

@ -1,34 +0,0 @@
{
"id": "visualize",
"version": "kibana",
"server": true,
"ui": true,
"requiredPlugins": [
"data",
"urlForwarding",
"navigation",
"savedObjects",
"visualizations",
"embeddable",
"dashboard",
"presentationUtil"
],
"optionalPlugins": [
"home",
"share",
"savedObjectsTaggingOss",
"usageCollection",
"spaces"
],
"requiredBundles": [
"kibanaUtils",
"kibanaReact",
"home",
"discover"
],
"owner": {
"name": "Vis Editors",
"githubTeam": "kibana-vis-editors"
},
"description": "Contains the visualize application which includes the listing page and the app frame, which will load the visualization's editor."
}

View file

@ -1,9 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export { VisualizeConstants, APP_NAME } from '../../common/constants';

View file

@ -1,20 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { PluginInitializerContext } from 'kibana/public';
import { VisualizePlugin, VisualizePluginSetup } from './plugin';
export { VisualizeConstants } from './application/visualize_constants';
export type { IEditorController, EditorRenderProps } from './application/types';
export type { VisualizePluginSetup };
export const plugin = (context: PluginInitializerContext) => {
return new VisualizePlugin(context);
};

View file

@ -1,271 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { i18n } from '@kbn/i18n';
import { createHashHistory } from 'history';
import { BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import {
AppMountParameters,
AppUpdater,
CoreSetup,
CoreStart,
Plugin,
PluginInitializerContext,
ScopedHistory,
DEFAULT_APP_CATEGORIES,
} from '../../../core/public';
import {
Storage,
createKbnUrlTracker,
createKbnUrlStateStorage,
withNotifyOnErrors,
} from '../../kibana_utils/public';
import { VisualizeConstants } from './application/visualize_constants';
import { DataPublicPluginStart, DataPublicPluginSetup, esFilters } from '../../data/public';
import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../home/public';
import type { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public';
import type { NavigationPublicPluginStart as NavigationStart } from '../../navigation/public';
import type { SharePluginStart, SharePluginSetup } from '../../share/public';
import type { UrlForwardingSetup, UrlForwardingStart } from '../../url_forwarding/public';
import type { VisualizationsStart } from '../../visualizations/public';
import type { VisualizeServices } from './application/types';
import type { SavedObjectsStart } from '../../saved_objects/public';
import type { EmbeddableStart } from '../../embeddable/public';
import type { DashboardStart } from '../../dashboard/public';
import type { SavedObjectTaggingOssPluginStart } from '../../saved_objects_tagging_oss/public';
import type { UsageCollectionStart } from '../../usage_collection/public';
import type { SpacesApi } from '../../../../x-pack/plugins/spaces/public';
import { setVisEditorsRegistry, setUISettings, setUsageCollector } from './services';
import { createVisEditorsRegistry, VisEditorsRegistry } from './vis_editors_registry';
import { VisualizeLocatorDefinition } from '../common/locator';
export interface VisualizePluginStartDependencies {
data: DataPublicPluginStart;
navigation: NavigationStart;
share?: SharePluginStart;
visualizations: VisualizationsStart;
embeddable: EmbeddableStart;
urlForwarding: UrlForwardingStart;
savedObjects: SavedObjectsStart;
dashboard: DashboardStart;
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
presentationUtil: PresentationUtilPluginStart;
usageCollection?: UsageCollectionStart;
spaces?: SpacesApi;
}
export interface VisualizePluginSetupDependencies {
home?: HomePublicPluginSetup;
urlForwarding: UrlForwardingSetup;
data: DataPublicPluginSetup;
share?: SharePluginSetup;
}
export interface VisualizePluginSetup {
visEditorsRegistry: VisEditorsRegistry;
}
export class VisualizePlugin
implements
Plugin<
VisualizePluginSetup,
void,
VisualizePluginSetupDependencies,
VisualizePluginStartDependencies
>
{
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
private stopUrlTracking: (() => void) | undefined = undefined;
private currentHistory: ScopedHistory | undefined = undefined;
private isLinkedToOriginatingApp: (() => boolean) | undefined = undefined;
private readonly visEditorsRegistry = createVisEditorsRegistry();
constructor(private initializerContext: PluginInitializerContext) {}
public setup(
core: CoreSetup<VisualizePluginStartDependencies>,
{ home, urlForwarding, data, share }: VisualizePluginSetupDependencies
) {
const {
appMounted,
appUnMounted,
stop: stopUrlTracker,
setActiveUrl,
restorePreviousUrl,
} = createKbnUrlTracker({
baseUrl: core.http.basePath.prepend(VisualizeConstants.VISUALIZE_BASE_PATH),
defaultSubUrl: '#/',
storageKey: `lastUrl:${core.http.basePath.get()}:visualize`,
navLinkUpdater$: this.appStateUpdater,
toastNotifications: core.notifications.toasts,
stateParams: [
{
kbnUrlKey: '_g',
stateUpdate$: data.query.state$.pipe(
filter(
({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval)
),
map(({ state }) => ({
...state,
filters: state.filters?.filter(esFilters.isFilterPinned),
}))
),
},
],
getHistory: () => this.currentHistory!,
onBeforeNavLinkSaved: (urlToSave: string) => {
if (this.isLinkedToOriginatingApp?.()) {
return core.http.basePath.prepend(VisualizeConstants.VISUALIZE_BASE_PATH);
}
return urlToSave;
},
});
this.stopUrlTracking = () => {
stopUrlTracker();
};
setUISettings(core.uiSettings);
core.application.register({
id: VisualizeConstants.APP_ID,
title: 'Visualize Library',
order: 8000,
euiIconType: 'logoKibana',
defaultPath: '#/',
category: DEFAULT_APP_CATEGORIES.kibana,
updater$: this.appStateUpdater.asObservable(),
// remove all references to visualize
mount: async (params: AppMountParameters) => {
const [coreStart, pluginsStart] = await core.getStartServices();
this.currentHistory = params.history;
// allows the urlTracker to only save URLs that are not linked to an originatingApp
this.isLinkedToOriginatingApp = () => {
return Boolean(
pluginsStart.embeddable
.getStateTransfer()
.getIncomingEditorState(VisualizeConstants.APP_ID)?.originatingApp
);
};
// make sure the index pattern list is up to date
pluginsStart.data.indexPatterns.clearCache();
// make sure a default index pattern exists
// if not, the page will be redirected to management and visualize won't be rendered
await pluginsStart.data.indexPatterns.ensureDefaultDataView();
appMounted();
// dispatch synthetic hash change event to update hash history objects
// this is necessary because hash updates triggered by using popState won't trigger this event naturally.
const unlistenParentHistory = params.history.listen(() => {
window.dispatchEvent(new HashChangeEvent('hashchange'));
});
/**
* current implementation uses 2 history objects:
* 1. the hash history (used for the react hash router)
* 2. and the scoped history (used for url tracking)
* this should be replaced to use only scoped history after moving legacy apps to browser routing
*/
const history = createHashHistory();
const services: VisualizeServices = {
...coreStart,
history,
kbnUrlStateStorage: createKbnUrlStateStorage({
history,
useHash: coreStart.uiSettings.get('state:storeInSessionStorage'),
...withNotifyOnErrors(coreStart.notifications.toasts),
}),
urlForwarding: pluginsStart.urlForwarding,
pluginInitializerContext: this.initializerContext,
chrome: coreStart.chrome,
data: pluginsStart.data,
localStorage: new Storage(localStorage),
navigation: pluginsStart.navigation,
share: pluginsStart.share,
toastNotifications: coreStart.notifications.toasts,
visualizeCapabilities: coreStart.application.capabilities.visualize,
dashboardCapabilities: coreStart.application.capabilities.dashboard,
visualizations: pluginsStart.visualizations,
embeddable: pluginsStart.embeddable,
stateTransferService: pluginsStart.embeddable.getStateTransfer(),
setActiveUrl,
createVisEmbeddableFromObject:
pluginsStart.visualizations.__LEGACY.createVisEmbeddableFromObject,
savedObjectsPublic: pluginsStart.savedObjects,
scopedHistory: params.history,
restorePreviousUrl,
dashboard: pluginsStart.dashboard,
setHeaderActionMenu: params.setHeaderActionMenu,
savedObjectsTagging: pluginsStart.savedObjectsTaggingOss?.getTaggingApi(),
presentationUtil: pluginsStart.presentationUtil,
usageCollection: pluginsStart.usageCollection,
getKibanaVersion: () => this.initializerContext.env.packageInfo.version,
spaces: pluginsStart.spaces,
};
params.element.classList.add('visAppWrapper');
const { renderApp } = await import('./application');
const unmount = renderApp(params, services);
return () => {
data.search.session.clear();
params.element.classList.remove('visAppWrapper');
unlistenParentHistory();
unmount();
appUnMounted();
};
},
});
urlForwarding.forwardApp('visualize', 'visualize');
if (home) {
home.featureCatalogue.register({
id: 'visualize',
title: 'Visualize Library',
description: i18n.translate('visualize.visualizeDescription', {
defaultMessage:
'Create visualizations and aggregate data stores in your Elasticsearch indices.',
}),
icon: 'visualizeApp',
path: `/app/visualize#${VisualizeConstants.LANDING_PAGE_PATH}`,
showOnHomePage: false,
category: FeatureCatalogueCategory.DATA,
});
}
if (share) {
share.url.locators.create(new VisualizeLocatorDefinition());
}
return {
visEditorsRegistry: this.visEditorsRegistry,
} as VisualizePluginSetup;
}
public start(core: CoreStart, { usageCollection }: VisualizePluginStartDependencies) {
setVisEditorsRegistry(this.visEditorsRegistry);
if (usageCollection) {
setUsageCollector(usageCollection);
}
}
stop() {
if (this.stopUrlTracking) {
this.stopUrlTracking();
}
}
}

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { createGetterSetter } from '../../../plugins/kibana_utils/public';
import type { IUiSettingsClient } from '../../../core/public';
import type { VisEditorsRegistry } from './vis_editors_registry';
import type { UsageCollectionStart } from '../../usage_collection/public';
export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');
export const [getUsageCollector, setUsageCollector] = createGetterSetter<UsageCollectionStart>(
'UsageCollection',
false
);
export const [getVisEditorsRegistry, setVisEditorsRegistry] =
createGetterSetter<VisEditorsRegistry>('VisEditorsRegistry');

View file

@ -1,13 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { PluginInitializerContext } from 'kibana/server';
import { VisualizeServerPlugin } from './plugin';
export const plugin = (initContext: PluginInitializerContext) =>
new VisualizeServerPlugin(initContext);

View file

@ -1,33 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from 'kibana/server';
import { capabilitiesProvider } from './capabilities_provider';
export class VisualizeServerPlugin implements Plugin<object, object> {
private readonly logger: Logger;
constructor(initializerContext: PluginInitializerContext) {
this.logger = initializerContext.logger.get();
}
public setup(core: CoreSetup) {
this.logger.debug('visualize: Setup');
core.capabilities.registerProvider(capabilitiesProvider);
return {};
}
public start(core: CoreStart) {
this.logger.debug('visualize: Started');
return {};
}
public stop() {}
}

View file

@ -1,30 +0,0 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./target/types",
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true
},
"include": ["common/**/*", "public/**/*", "server/**/*", "../../../typings/**/*"],
"references": [
{ "path": "../../core/tsconfig.json" },
{ "path": "../data/tsconfig.json" },
{ "path": "../url_forwarding/tsconfig.json" },
{ "path": "../navigation/tsconfig.json" },
{ "path": "../saved_objects/tsconfig.json" },
{ "path": "../visualizations/tsconfig.json" },
{ "path": "../embeddable/tsconfig.json" },
{ "path": "../dashboard/tsconfig.json" },
{ "path": "../ui_actions/tsconfig.json" },
{ "path": "../home/tsconfig.json" },
{ "path": "../share/tsconfig.json" },
{ "path": "../saved_objects_tagging_oss/tsconfig.json" },
{ "path": "../kibana_utils/tsconfig.json" },
{ "path": "../kibana_react/tsconfig.json" },
{ "path": "../home/tsconfig.json" },
{ "path": "../presentation_util/tsconfig.json" },
{ "path": "../discover/tsconfig.json" },
{ "path": "../../../x-pack/plugins/spaces/tsconfig.json" },
]
}

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { VisualizeConstants } from '../../../../src/plugins/visualize/public/application/visualize_constants';
import { VisualizeConstants } from '../../../../src/plugins/visualizations/common/constants';
import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../src/plugins/visualizations/common/constants';
import { FtrProviderContext } from '../../ftr_provider_context';

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { PIE_CHART_VIS_NAME } from '../../page_objects/dashboard_page';
import { VisualizeConstants } from '../../../../src/plugins/visualize/public/application/visualize_constants';
import { VisualizeConstants } from '../../../../src/plugins/visualizations/common/constants';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {

View file

@ -7,7 +7,7 @@
*/
import { FtrService } from '../ftr_provider_context';
import { VisualizeConstants } from '../../../src/plugins/visualize/public/application/visualize_constants';
import { VisualizeConstants } from '../../../src/plugins/visualizations/common/constants';
import { FORMATS_UI_SETTINGS } from '../../../src/plugins/field_formats/common';
// TODO: Remove & Refactor to use the TTV page objects

View file

@ -52,7 +52,7 @@
{ "path": "../src/plugins/url_forwarding/tsconfig.json" },
{ "path": "../src/plugins/usage_collection/tsconfig.json" },
{ "path": "../src/plugins/data_view_management/tsconfig.json" },
{ "path": "../src/plugins/visualize/tsconfig.json" },
{ "path": "../src/plugins/visualizations/tsconfig.json" },
{ "path": "interactive_setup_api_integration/fixtures/test_endpoints/tsconfig.json" },
{ "path": "plugin_functional/plugins/core_app_status/tsconfig.json" },
{ "path": "plugin_functional/plugins/core_provider_plugin/tsconfig.json" },

View file

@ -5145,13 +5145,24 @@
"visTypeXy.thresholdLine.style.fullText": "完全",
"visualizations.advancedSettings.visualizeEnableLabsText": "ユーザーが実験的なビジュアライゼーションを作成、表示、編集できるようになります。無効の場合、\n ユーザーは本番準備が整ったビジュアライゼーションのみを利用できます。",
"visualizations.advancedSettings.visualizeEnableLabsTitle": "実験的なビジュアライゼーションを有効にする",
"visualizations.badge.readOnly.text": "読み取り専用",
"visualizations.badge.readOnly.tooltip": "ビジュアライゼーションをライブラリに保存できません",
"visualizations.byValue_pageHeading": "{originatingApp}アプリに埋め込まれた{chartType}タイプのビジュアライゼーション",
"visualizations.confirmModal.confirmTextDescription": "変更を保存せずにVisualizeエディターから移動しますか",
"visualizations.confirmModal.title": "保存されていない変更",
"visualizations.createVisualization.failedToLoadErrorMessage": "ビジュアライゼーションを読み込めませんでした",
"visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "indexPatternまたはsavedSearchIdが必要です",
"visualizations.createVisualization.noVisTypeErrorMessage": "有効なビジュアライゼーションタイプを指定してください",
"visualizations.disabledLabVisualizationLink": "ドキュメンテーションを表示",
"visualizations.disabledLabVisualizationMessage": "ラボビジュアライゼーションを表示するには、高度な設定でラボモードをオンにしてください。",
"visualizations.disabledLabVisualizationTitle": "{title} はラボビジュアライゼーションです。",
"visualizations.displayName": "ビジュアライゼーション",
"visualizations.editor.createBreadcrumb": "作成",
"visualizations.editor.defaultEditBreadcrumbText": "ビジュアライゼーションを編集",
"visualizations.embeddable.inspectorTitle": "インスペクター",
"visualizations.embeddable.legacyURLConflict.errorMessage": "このビジュアライゼーションにはレガシーエイリアスと同じURLがあります。このエラーを解決するには、エイリアスを無効にしてください{json}",
"visualizations.embeddable.placeholderTitle": "プレースホルダータイトル",
"visualizations.experimentalVisInfoText": "このビジュアライゼーションはまだ実験段階であり、オフィシャルGA機能のサポートSLAが適用されません。フィードバックがある場合は、{githubLink}で問題を報告してください。",
"visualizations.function.range.from.help": "範囲の開始",
"visualizations.function.range.help": "範囲オブジェクトを生成します",
"visualizations.function.range.to.help": "範囲の終了",
@ -5161,11 +5172,29 @@
"visualizations.function.visDimension.formatParams.help": "フォーマットパラメーター",
"visualizations.function.visDimension.help": "visConfig ディメンションオブジェクトを生成します",
"visualizations.function.xyDimension.aggType.help": "集約タイプ",
"visualizations.function.xydimension.help": "XYディメンションオブジェクトを生成します",
"visualizations.function.xyDimension.label.help": "ラベル",
"visualizations.function.xyDimension.params.help": "パラメーター",
"visualizations.function.xyDimension.visDimension.help": "ディメンションオブジェクト構成",
"visualizations.function.xydimension.help": "XYディメンションオブジェクトを生成します",
"visualizations.helpMenu.appName": "Visualizeライブラリ",
"visualizations.initializeWithoutIndexPatternErrorMessage": "インデックスパターンなしで集約を初期化しようとしています",
"visualizations.legacyUrlConflict.objectNoun": "{visName}ビジュアライゼーション",
"visualizations.linkedToSearch.unlinkSuccessNotificationText": "保存された検索「{searchTitle}」からリンクが解除されました",
"visualizations.listing.betaTitle": "ベータ",
"visualizations.listing.betaTooltip": "このビジュアライゼーションはベータ段階で、変更される可能性があります。デザインとコードはオフィシャルGA機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャルGA機能のSLAが適用されません",
"visualizations.listing.breadcrumb": "Visualizeライブラリ",
"visualizations.listing.createNew.createButtonLabel": "新規ビジュアライゼーションを追加",
"visualizations.listing.createNew.description": "データに基づき異なるビジュアライゼーションを作成できます。",
"visualizations.listing.createNew.title": "最初のビジュアライゼーションの作成",
"visualizations.listing.experimentalTitle": "実験的",
"visualizations.listing.experimentalTooltip": "このビジュアライゼーションは今後のリリースで変更または削除される可能性があり、SLA のサポート対象になりません。",
"visualizations.listing.table.descriptionColumnName": "説明",
"visualizations.listing.table.entityName": "ビジュアライゼーション",
"visualizations.listing.table.entityNamePlural": "ビジュアライゼーション",
"visualizations.listing.table.listTitle": "Visualizeライブラリ",
"visualizations.listing.table.titleColumnName": "タイトル",
"visualizations.listing.table.typeColumnName": "型",
"visualizations.listingPageTitle": "Visualizeライブラリ",
"visualizations.newVisWizard.aggBasedGroupDescription": "クラシック Visualize ライブラリを使用して、アグリゲーションに基づいてグラフを作成します。",
"visualizations.newVisWizard.aggBasedGroupTitle": "アグリゲーションに基づく",
"visualizations.newVisWizard.chooseSourceTitle": "ソースの選択",
@ -5182,69 +5211,40 @@
"visualizations.newVisWizard.searchSelection.savedObjectType.search": "保存検索",
"visualizations.newVisWizard.title": "新規ビジュアライゼーション",
"visualizations.newVisWizard.toolsGroupTitle": "ツール",
"visualizations.noMatchRoute.bannerText": "Visualizeアプリケーションはこのルートを認識できません。{route}",
"visualizations.noMatchRoute.bannerTitleText": "ページが見つかりません",
"visualizations.noResultsFoundTitle": "結果が見つかりませんでした",
"visualizations.pageHeading": "{chartName} {chartType}ビジュアライゼーション",
"visualizations.reporting.defaultReportTitle": "ビジュアライゼーション[{date}]",
"visualizations.savedObjectName": "ビジュアライゼーション",
"visualizations.savingVisualizationFailed.errorMsg": "ビジュアライゼーションの保存が失敗しました",
"visualizations.topNavMenu.cancelAndReturnButtonTooltip": "完了する前に変更を破棄",
"visualizations.topNavMenu.cancelButtonAriaLabel": "変更を保存せずに最後に使用していたアプリに戻る",
"visualizations.topNavMenu.cancelButtonLabel": "キャンセル",
"visualizations.topNavMenu.openInspectorButtonAriaLabel": "ビジュアライゼーションのインスペクターを開く",
"visualizations.topNavMenu.openInspectorButtonLabel": "検査",
"visualizations.topNavMenu.openInspectorDisabledButtonTooltip": "このビジュアライゼーションはインスペクターをサポートしていません。",
"visualizations.topNavMenu.saveAndReturnVisualizationButtonAriaLabel": "可視化の編集が完了し、前回使用していたアプリに戻ります",
"visualizations.topNavMenu.saveAndReturnVisualizationButtonLabel": "保存して戻る",
"visualizations.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip": "完了する前に変更を適用または破棄",
"visualizations.topNavMenu.saveVisualization.failureNotificationText": "「{visTitle}」の保存中にエラーが発生しました",
"visualizations.topNavMenu.saveVisualization.successNotificationText": "保存された'{visTitle}'",
"visualizations.topNavMenu.saveVisualizationAsButtonLabel": "名前を付けて保存",
"visualizations.topNavMenu.saveVisualizationButtonAriaLabel": "ビジュアライゼーションを保存",
"visualizations.topNavMenu.saveVisualizationButtonLabel": "保存",
"visualizations.topNavMenu.saveVisualizationDisabledButtonTooltip": "保存する前に変更を適用または破棄",
"visualizations.topNavMenu.saveVisualizationObjectType": "ビジュアライゼーション",
"visualizations.topNavMenu.saveVisualizationToLibraryButtonLabel": "ライブラリに保存",
"visualizations.topNavMenu.shareVisualizationButtonAriaLabel": "ビジュアライゼーションを共有",
"visualizations.topNavMenu.shareVisualizationButtonLabel": "共有",
"visualizations.topNavMenu.updatePanel": "{originatingAppName}でパネルを更新",
"visualizations.visualizationLoadingFailedErrorMessage": "ビジュアライゼーションを読み込めませんでした",
"visualizations.visualizationTypeInvalidMessage": "無効なビジュアライゼーションタイプ \"{visType}\"",
"visualize.badge.readOnly.text": "読み取り専用",
"visualize.badge.readOnly.tooltip": "ビジュアライゼーションをライブラリに保存できません",
"visualize.byValue_pageHeading": "{originatingApp}アプリに埋め込まれた{chartType}タイプのビジュアライゼーション",
"visualize.confirmModal.confirmTextDescription": "変更を保存せずにVisualizeエディターから移動しますか",
"visualize.confirmModal.title": "保存されていない変更",
"visualize.createVisualization.failedToLoadErrorMessage": "ビジュアライゼーションを読み込めませんでした",
"visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "indexPatternまたはsavedSearchIdが必要です",
"visualize.createVisualization.noVisTypeErrorMessage": "有効なビジュアライゼーションタイプを指定してください",
"visualize.editor.createBreadcrumb": "作成",
"visualize.editor.defaultEditBreadcrumbText": "ビジュアライゼーションを編集",
"visualize.experimentalVisInfoText": "このビジュアライゼーションはまだ実験段階であり、オフィシャルGA機能のサポートSLAが適用されません。フィードバックがある場合は、{githubLink}で問題を報告してください。",
"visualize.helpMenu.appName": "Visualizeライブラリ",
"visualize.legacyUrlConflict.objectNoun": "{visName}ビジュアライゼーション",
"visualize.linkedToSearch.unlinkSuccessNotificationText": "保存された検索「{searchTitle}」からリンクが解除されました",
"visualize.listing.betaTitle": "ベータ",
"visualize.listing.betaTooltip": "このビジュアライゼーションはベータ段階で、変更される可能性があります。デザインとコードはオフィシャルGA機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャルGA機能のSLAが適用されません",
"visualize.listing.breadcrumb": "Visualizeライブラリ",
"visualize.listing.createNew.createButtonLabel": "新規ビジュアライゼーションを追加",
"visualize.listing.createNew.description": "データに基づき異なるビジュアライゼーションを作成できます。",
"visualize.listing.createNew.title": "最初のビジュアライゼーションの作成",
"visualize.listing.experimentalTitle": "実験的",
"visualize.listing.experimentalTooltip": "このビジュアライゼーションは今後のリリースで変更または削除される可能性があり、SLA のサポート対象になりません。",
"visualize.listing.table.descriptionColumnName": "説明",
"visualize.listing.table.entityName": "ビジュアライゼーション",
"visualize.listing.table.entityNamePlural": "ビジュアライゼーション",
"visualize.listing.table.listTitle": "Visualizeライブラリ",
"visualize.listing.table.titleColumnName": "タイトル",
"visualize.listing.table.typeColumnName": "型",
"visualize.listingPageTitle": "Visualizeライブラリ",
"visualize.noMatchRoute.bannerText": "Visualizeアプリケーションはこのルートを認識できません。{route}",
"visualize.noMatchRoute.bannerTitleText": "ページが見つかりません",
"visualize.pageHeading": "{chartName} {chartType}ビジュアライゼーション",
"visualize.reporting.defaultReportTitle": "ビジュアライゼーション[{date}]",
"visualize.topNavMenu.cancelAndReturnButtonTooltip": "完了する前に変更を破棄",
"visualize.topNavMenu.cancelButtonAriaLabel": "変更を保存せずに最後に使用していたアプリに戻る",
"visualize.topNavMenu.cancelButtonLabel": "キャンセル",
"visualize.topNavMenu.openInspectorButtonAriaLabel": "ビジュアライゼーションのインスペクターを開く",
"visualize.topNavMenu.openInspectorButtonLabel": "検査",
"visualize.topNavMenu.openInspectorDisabledButtonTooltip": "このビジュアライゼーションはインスペクターをサポートしていません。",
"visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel": "可視化の編集が完了し、前回使用していたアプリに戻ります",
"visualize.topNavMenu.saveAndReturnVisualizationButtonLabel": "保存して戻る",
"visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip": "完了する前に変更を適用または破棄",
"visualize.topNavMenu.saveVisualization.failureNotificationText": "「{visTitle}」の保存中にエラーが発生しました",
"visualize.topNavMenu.saveVisualization.successNotificationText": "保存された'{visTitle}'",
"visualize.topNavMenu.saveVisualizationAsButtonLabel": "名前を付けて保存",
"visualize.topNavMenu.saveVisualizationButtonAriaLabel": "ビジュアライゼーションを保存",
"visualize.topNavMenu.saveVisualizationButtonLabel": "保存",
"visualize.topNavMenu.saveVisualizationDisabledButtonTooltip": "保存する前に変更を適用または破棄",
"visualize.topNavMenu.saveVisualizationObjectType": "ビジュアライゼーション",
"visualize.topNavMenu.saveVisualizationToLibraryButtonLabel": "ライブラリに保存",
"visualize.topNavMenu.shareVisualizationButtonAriaLabel": "ビジュアライゼーションを共有",
"visualize.topNavMenu.shareVisualizationButtonLabel": "共有",
"visualize.topNavMenu.updatePanel": "{originatingAppName}でパネルを更新",
"visualize.visualizationLoadingFailedErrorMessage": "ビジュアライゼーションを読み込めませんでした",
"visualize.visualizeDescription": "ビジュアライゼーションを作成してElasticsearchインデックスに保存されたデータをアグリゲーションします。",
"visualize.visualizeListingBreadcrumbsTitle": "Visualizeライブラリ",
"visualize.visualizeListingDashboardAppName": "ダッシュボードアプリケーション",
"visualize.visualizeListingDashboardFlowDescription": "ダッシュボードを作成しますか?{dashboardApp}から直接ビジュアライゼーションを作成して追加します。",
"visualize.visualizeListingDeleteErrorTitle": "ビジュアライゼーションの削除中にエラーが発生",
"visualizations.visualizeDescription": "ビジュアライゼーションを作成してElasticsearchインデックスに保存されたデータをアグリゲーションします。",
"visualizations.visualizeListingBreadcrumbsTitle": "Visualizeライブラリ",
"visualizations.visualizeListingDashboardAppName": "ダッシュボードアプリケーション",
"visualizations.visualizeListingDashboardFlowDescription": "ダッシュボードを作成しますか?{dashboardApp}から直接ビジュアライゼーションを作成して追加します。",
"visualizations.visualizeListingDeleteErrorTitle": "ビジュアライゼーションの削除中にエラーが発生",
"xpack.actions.actionTypeRegistry.get.missingActionTypeErrorMessage": "アクションタイプ「{id}」は登録されていません。",
"xpack.actions.actionTypeRegistry.register.duplicateActionTypeErrorMessage": "アクションタイプ「{id}」はすでに登録されています。",
"xpack.actions.alertHistoryEsIndexConnector.name": "アラート履歴Elasticsearchインデックス",

View file

@ -5178,13 +5178,24 @@
"visTypeXy.thresholdLine.style.fullText": "实线",
"visualizations.advancedSettings.visualizeEnableLabsText": "允许用户创建、查看和编辑实验性可视化。如果禁用,\n 仅被视为生产就绪的可视化可供用户使用。",
"visualizations.advancedSettings.visualizeEnableLabsTitle": "启用实验性可视化",
"visualizations.badge.readOnly.text": "只读",
"visualizations.badge.readOnly.tooltip": "无法将可视化保存到库",
"visualizations.byValue_pageHeading": "已嵌入到 {originatingApp} 应用中的 {chartType} 类型可视化",
"visualizations.confirmModal.confirmTextDescription": "离开 Visualize 编辑器而不保存更改?",
"visualizations.confirmModal.title": "未保存的更改",
"visualizations.createVisualization.failedToLoadErrorMessage": "无法加载可视化",
"visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "必须提供 indexPattern 或 savedSearchId",
"visualizations.createVisualization.noVisTypeErrorMessage": "必须提供有效的可视化类型",
"visualizations.disabledLabVisualizationLink": "阅读文档",
"visualizations.disabledLabVisualizationMessage": "请在高级设置中打开实验模式,以查看实验性可视化。",
"visualizations.disabledLabVisualizationTitle": "{title} 为实验室可视化。",
"visualizations.displayName": "可视化",
"visualizations.editor.createBreadcrumb": "创建",
"visualizations.editor.defaultEditBreadcrumbText": "编辑可视化",
"visualizations.embeddable.inspectorTitle": "检查器",
"visualizations.embeddable.legacyURLConflict.errorMessage": "此可视化具有与旧版别名相同的 URL。请禁用别名以解决此错误{json}",
"visualizations.embeddable.placeholderTitle": "占位符标题",
"visualizations.experimentalVisInfoText": "此可视化为试验性功能,不受正式发行版功能支持 SLA 的约束。如欲提供反馈,请在 {githubLink} 中创建问题。",
"visualizations.function.range.from.help": "范围起始",
"visualizations.function.range.help": "生成范围对象",
"visualizations.function.range.to.help": "范围结束",
@ -5194,11 +5205,29 @@
"visualizations.function.visDimension.formatParams.help": "格式参数",
"visualizations.function.visDimension.help": "生成 visConfig 维度对象",
"visualizations.function.xyDimension.aggType.help": "聚合类型",
"visualizations.function.xydimension.help": "生成 xy 维度对象",
"visualizations.function.xyDimension.label.help": "标签",
"visualizations.function.xyDimension.params.help": "参数",
"visualizations.function.xyDimension.visDimension.help": "维度对象配置",
"visualizations.function.xydimension.help": "生成 xy 维度对象",
"visualizations.helpMenu.appName": "Visualize 库",
"visualizations.initializeWithoutIndexPatternErrorMessage": "正在尝试在不使用索引模式的情况下初始化聚合",
"visualizations.legacyUrlConflict.objectNoun": "{visName} 可视化",
"visualizations.linkedToSearch.unlinkSuccessNotificationText": "已取消与已保存搜索“{searchTitle}”的链接",
"visualizations.listing.betaTitle": "公测版",
"visualizations.listing.betaTooltip": "此可视化为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束",
"visualizations.listing.breadcrumb": "Visualize 库",
"visualizations.listing.createNew.createButtonLabel": "新建可视化",
"visualizations.listing.createNew.description": "可以根据您的数据创建不同的可视化。",
"visualizations.listing.createNew.title": "创建您的首个可视化",
"visualizations.listing.experimentalTitle": "实验性",
"visualizations.listing.experimentalTooltip": "未来版本可能会更改或删除此可视化,其不受支持 SLA 的约束。",
"visualizations.listing.table.descriptionColumnName": "描述",
"visualizations.listing.table.entityName": "可视化",
"visualizations.listing.table.entityNamePlural": "可视化",
"visualizations.listing.table.listTitle": "Visualize 库",
"visualizations.listing.table.titleColumnName": "标题",
"visualizations.listing.table.typeColumnName": "类型",
"visualizations.listingPageTitle": "Visualize 库",
"visualizations.newVisWizard.aggBasedGroupDescription": "使用我们的经典可视化库,基于聚合创建图表。",
"visualizations.newVisWizard.aggBasedGroupTitle": "基于聚合",
"visualizations.newVisWizard.chooseSourceTitle": "选择源",
@ -5216,69 +5245,40 @@
"visualizations.newVisWizard.searchSelection.savedObjectType.search": "已保存搜索",
"visualizations.newVisWizard.title": "新建可视化",
"visualizations.newVisWizard.toolsGroupTitle": "工具",
"visualizations.noMatchRoute.bannerText": "Visualize 应用程序无法识别此路由:{route}。",
"visualizations.noMatchRoute.bannerTitleText": "未找到页面",
"visualizations.noResultsFoundTitle": "找不到结果",
"visualizations.pageHeading": "{chartName} {chartType} 可视化",
"visualizations.reporting.defaultReportTitle": "可视化 [{date}]",
"visualizations.savedObjectName": "可视化",
"visualizations.savingVisualizationFailed.errorMsg": "保存可视化失败",
"visualizations.topNavMenu.cancelAndReturnButtonTooltip": "完成前放弃所做的更改",
"visualizations.topNavMenu.cancelButtonAriaLabel": "返回到上一个应用而不保存更改",
"visualizations.topNavMenu.cancelButtonLabel": "取消",
"visualizations.topNavMenu.openInspectorButtonAriaLabel": "打开检查器查看可视化",
"visualizations.topNavMenu.openInspectorButtonLabel": "检查",
"visualizations.topNavMenu.openInspectorDisabledButtonTooltip": "此可视化不支持任何检查器。",
"visualizations.topNavMenu.saveAndReturnVisualizationButtonAriaLabel": "完成编辑可视化并返回到最后一个应用",
"visualizations.topNavMenu.saveAndReturnVisualizationButtonLabel": "保存并返回",
"visualizations.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip": "完成前应用或放弃所做更改",
"visualizations.topNavMenu.saveVisualization.failureNotificationText": "保存“{visTitle}”时出错",
"visualizations.topNavMenu.saveVisualization.successNotificationText": "已保存“{visTitle}”",
"visualizations.topNavMenu.saveVisualizationAsButtonLabel": "另存为",
"visualizations.topNavMenu.saveVisualizationButtonAriaLabel": "保存可视化",
"visualizations.topNavMenu.saveVisualizationButtonLabel": "保存",
"visualizations.topNavMenu.saveVisualizationDisabledButtonTooltip": "保存前应用或放弃所做更改",
"visualizations.topNavMenu.saveVisualizationObjectType": "可视化",
"visualizations.topNavMenu.saveVisualizationToLibraryButtonLabel": "保存到库",
"visualizations.topNavMenu.shareVisualizationButtonAriaLabel": "共享可视化",
"visualizations.topNavMenu.shareVisualizationButtonLabel": "共享",
"visualizations.topNavMenu.updatePanel": "更新 {originatingAppName} 中的面板",
"visualizations.visualizationLoadingFailedErrorMessage": "无法加载可视化",
"visualizations.visualizationTypeInvalidMessage": "无效的可视化类型“{visType}”",
"visualize.badge.readOnly.text": "只读",
"visualize.badge.readOnly.tooltip": "无法将可视化保存到库",
"visualize.byValue_pageHeading": "已嵌入到 {originatingApp} 应用中的 {chartType} 类型可视化",
"visualize.confirmModal.confirmTextDescription": "离开 Visualize 编辑器而不保存更改?",
"visualize.confirmModal.title": "未保存的更改",
"visualize.createVisualization.failedToLoadErrorMessage": "无法加载可视化",
"visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "必须提供 indexPattern 或 savedSearchId",
"visualize.createVisualization.noVisTypeErrorMessage": "必须提供有效的可视化类型",
"visualize.editor.createBreadcrumb": "创建",
"visualize.editor.defaultEditBreadcrumbText": "编辑可视化",
"visualize.experimentalVisInfoText": "此可视化为试验性功能,不受正式发行版功能支持 SLA 的约束。如欲提供反馈,请在 {githubLink} 中创建问题。",
"visualize.helpMenu.appName": "Visualize 库",
"visualize.legacyUrlConflict.objectNoun": "{visName} 可视化",
"visualize.linkedToSearch.unlinkSuccessNotificationText": "已取消与已保存搜索“{searchTitle}”的链接",
"visualize.listing.betaTitle": "公测版",
"visualize.listing.betaTooltip": "此可视化为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束",
"visualize.listing.breadcrumb": "Visualize 库",
"visualize.listing.createNew.createButtonLabel": "新建可视化",
"visualize.listing.createNew.description": "可以根据您的数据创建不同的可视化。",
"visualize.listing.createNew.title": "创建您的首个可视化",
"visualize.listing.experimentalTitle": "实验性",
"visualize.listing.experimentalTooltip": "未来版本可能会更改或删除此可视化,其不受支持 SLA 的约束。",
"visualize.listing.table.descriptionColumnName": "描述",
"visualize.listing.table.entityName": "可视化",
"visualize.listing.table.entityNamePlural": "可视化",
"visualize.listing.table.listTitle": "Visualize 库",
"visualize.listing.table.titleColumnName": "标题",
"visualize.listing.table.typeColumnName": "类型",
"visualize.listingPageTitle": "Visualize 库",
"visualize.noMatchRoute.bannerText": "Visualize 应用程序无法识别此路由:{route}。",
"visualize.noMatchRoute.bannerTitleText": "未找到页面",
"visualize.pageHeading": "{chartName} {chartType} 可视化",
"visualize.reporting.defaultReportTitle": "可视化 [{date}]",
"visualize.topNavMenu.cancelAndReturnButtonTooltip": "完成前放弃所做的更改",
"visualize.topNavMenu.cancelButtonAriaLabel": "返回到上一个应用而不保存更改",
"visualize.topNavMenu.cancelButtonLabel": "取消",
"visualize.topNavMenu.openInspectorButtonAriaLabel": "打开检查器查看可视化",
"visualize.topNavMenu.openInspectorButtonLabel": "检查",
"visualize.topNavMenu.openInspectorDisabledButtonTooltip": "此可视化不支持任何检查器。",
"visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel": "完成编辑可视化并返回到最后一个应用",
"visualize.topNavMenu.saveAndReturnVisualizationButtonLabel": "保存并返回",
"visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip": "完成前应用或放弃所做更改",
"visualize.topNavMenu.saveVisualization.failureNotificationText": "保存“{visTitle}”时出错",
"visualize.topNavMenu.saveVisualization.successNotificationText": "已保存“{visTitle}”",
"visualize.topNavMenu.saveVisualizationAsButtonLabel": "另存为",
"visualize.topNavMenu.saveVisualizationButtonAriaLabel": "保存可视化",
"visualize.topNavMenu.saveVisualizationButtonLabel": "保存",
"visualize.topNavMenu.saveVisualizationDisabledButtonTooltip": "保存前应用或放弃所做更改",
"visualize.topNavMenu.saveVisualizationObjectType": "可视化",
"visualize.topNavMenu.saveVisualizationToLibraryButtonLabel": "保存到库",
"visualize.topNavMenu.shareVisualizationButtonAriaLabel": "共享可视化",
"visualize.topNavMenu.shareVisualizationButtonLabel": "共享",
"visualize.topNavMenu.updatePanel": "更新 {originatingAppName} 中的面板",
"visualize.visualizationLoadingFailedErrorMessage": "无法加载可视化",
"visualize.visualizeDescription": "创建可视化并聚合在 Elasticsearch 索引中的数据存储。",
"visualize.visualizeListingBreadcrumbsTitle": "Visualize 库",
"visualize.visualizeListingDashboardAppName": "Dashboard 应用程序",
"visualize.visualizeListingDashboardFlowDescription": "构建仪表板?从 {dashboardApp}创建和添加您的可视化。",
"visualize.visualizeListingDeleteErrorTitle": "删除可视化时出错",
"visualizations.visualizeDescription": "创建可视化并聚合在 Elasticsearch 索引中的数据存储。",
"visualizations.visualizeListingBreadcrumbsTitle": "Visualize 库",
"visualizations.visualizeListingDashboardAppName": "Dashboard 应用程序",
"visualizations.visualizeListingDashboardFlowDescription": "构建仪表板?从 {dashboardApp}创建和添加您的可视化。",
"visualizations.visualizeListingDeleteErrorTitle": "删除可视化时出错",
"xpack.actions.actionTypeRegistry.get.missingActionTypeErrorMessage": "操作类型“{id}”未注册。",
"xpack.actions.actionTypeRegistry.register.duplicateActionTypeErrorMessage": "操作类型“{id}”已注册。",
"xpack.actions.alertHistoryEsIndexConnector.name": "告警历史记录 Elasticsearch 索引",

View file

@ -6,7 +6,7 @@
*/
import expect from '@kbn/expect';
import { VisualizeConstants } from '../../../../../../src/plugins/visualize/public/application/visualize_constants';
import { VisualizeConstants } from '../../../../../../src/plugins/visualizations/common/constants';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getPageObjects, getService }: FtrProviderContext) {