diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index afe05dbfa4694..e04d45f77db5d 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -1178,10 +1178,10 @@ import { setup, start } from '../core_plugins/visualizations/public/legacy'; | `ui/index_patterns` | `data.indexPatterns` | still in progress | | `ui/registry/field_formats` | `data.fieldFormats` | | | `ui/registry/feature_catalogue` | `home.featureCatalogue.register` | Must add `home` as a dependency in your kibana.json. | -| `ui/registry/vis_types` | `visualizations.types` | -- | -| `ui/vis` | `visualizations.types` | -- | +| `ui/registry/vis_types` | `visualizations` | -- | +| `ui/vis` | `visualizations` | -- | | `ui/share` | `share` | `showShareContextMenu` is now called `toggleShareContextMenu`, `ShareContextMenuExtensionsRegistryProvider` is now called `register` | -| `ui/vis/vis_factory` | `visualizations.types` | -- | +| `ui/vis/vis_factory` | `visualizations` | -- | | `ui/vis/vis_filters` | `visualizations.filters` | -- | | `ui/utils/parse_es_interval` | `import { parseEsInterval } from '../data/public'` | `parseEsInterval`, `ParsedInterval`, `InvalidEsCalendarIntervalError`, `InvalidEsIntervalFormatError` items were moved to the `Data Plugin` as a static code | diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/calculate_object_hash.d.ts b/src/core/server/metrics/collectors/mocks.ts similarity index 72% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/calculate_object_hash.d.ts rename to src/core/server/metrics/collectors/mocks.ts index d2d11c14a3e5f..d1eb15637779a 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/calculate_object_hash.d.ts +++ b/src/core/server/metrics/collectors/mocks.ts @@ -17,4 +17,19 @@ * under the License. */ -export function calculateObjectHash(obj: object): string; +import { MetricsCollector } from './types'; + +const createMock = () => { + const mocked: jest.Mocked> = { + collect: jest.fn(), + reset: jest.fn(), + }; + + mocked.collect.mockResolvedValue({}); + + return mocked; +}; + +export const collectorMock = { + create: createMock, +}; diff --git a/src/core/server/metrics/collectors/os.ts b/src/core/server/metrics/collectors/os.ts index d3d9bb0be86fa..59bef9d8ddd2b 100644 --- a/src/core/server/metrics/collectors/os.ts +++ b/src/core/server/metrics/collectors/os.ts @@ -57,4 +57,6 @@ export class OsMetricsCollector implements MetricsCollector { return metrics; } + + public reset() {} } diff --git a/src/core/server/metrics/collectors/process.ts b/src/core/server/metrics/collectors/process.ts index aa68abaf74e41..a3b59a7cc8b7c 100644 --- a/src/core/server/metrics/collectors/process.ts +++ b/src/core/server/metrics/collectors/process.ts @@ -40,6 +40,8 @@ export class ProcessMetricsCollector implements MetricsCollector => { diff --git a/src/core/server/metrics/collectors/server.ts b/src/core/server/metrics/collectors/server.ts index e46ac2f653df6..84204d0466ff3 100644 --- a/src/core/server/metrics/collectors/server.ts +++ b/src/core/server/metrics/collectors/server.ts @@ -26,12 +26,12 @@ interface ServerResponseTime { } export class ServerMetricsCollector implements MetricsCollector { - private readonly requests: OpsServerMetrics['requests'] = { + private requests: OpsServerMetrics['requests'] = { disconnects: 0, total: 0, statusCodes: {}, }; - private readonly responseTimes: ServerResponseTime = { + private responseTimes: ServerResponseTime = { count: 0, total: 0, max: 0, @@ -77,4 +77,17 @@ export class ServerMetricsCollector implements MetricsCollector { + /** collect the data currently gathered by the collector */ collect(): Promise; + /** reset the internal state of the collector */ + reset(): void; } /** diff --git a/src/core/server/metrics/integration_tests/server_collector.test.ts b/src/core/server/metrics/integration_tests/server_collector.test.ts index 6baf95894b9b4..dd5c256cf1600 100644 --- a/src/core/server/metrics/integration_tests/server_collector.test.ts +++ b/src/core/server/metrics/integration_tests/server_collector.test.ts @@ -200,4 +200,80 @@ describe('ServerMetricsCollector', () => { metrics = await collector.collect(); expect(metrics.concurrent_connections).toEqual(0); }); + + describe('#reset', () => { + it('reset the requests state', async () => { + router.get({ path: '/', validate: false }, async (ctx, req, res) => { + return res.ok({ body: '' }); + }); + await server.start(); + + await sendGet('/'); + await sendGet('/'); + await sendGet('/not-found'); + + let metrics = await collector.collect(); + + expect(metrics.requests).toEqual({ + total: 3, + disconnects: 0, + statusCodes: { + '200': 2, + '404': 1, + }, + }); + + collector.reset(); + metrics = await collector.collect(); + + expect(metrics.requests).toEqual({ + total: 0, + disconnects: 0, + statusCodes: {}, + }); + + await sendGet('/'); + await sendGet('/not-found'); + + metrics = await collector.collect(); + + expect(metrics.requests).toEqual({ + total: 2, + disconnects: 0, + statusCodes: { + '200': 1, + '404': 1, + }, + }); + }); + + it('resets the response times', async () => { + router.get({ path: '/no-delay', validate: false }, async (ctx, req, res) => { + return res.ok({ body: '' }); + }); + router.get({ path: '/500-ms', validate: false }, async (ctx, req, res) => { + await delay(500); + return res.ok({ body: '' }); + }); + + await server.start(); + + await Promise.all([sendGet('/no-delay'), sendGet('/500-ms')]); + let metrics = await collector.collect(); + + expect(metrics.response_times.avg_in_millis).toBeGreaterThanOrEqual(250); + expect(metrics.response_times.max_in_millis).toBeGreaterThanOrEqual(500); + + collector.reset(); + metrics = await collector.collect(); + expect(metrics.response_times.avg_in_millis).toBe(0); + expect(metrics.response_times.max_in_millis).toBeGreaterThanOrEqual(0); + + await Promise.all([sendGet('/500-ms'), sendGet('/500-ms')]); + metrics = await collector.collect(); + + expect(metrics.response_times.avg_in_millis).toBeGreaterThanOrEqual(500); + expect(metrics.response_times.max_in_millis).toBeGreaterThanOrEqual(500); + }); + }); }); diff --git a/src/core/server/metrics/metrics_service.test.mocks.ts b/src/core/server/metrics/metrics_service.test.mocks.ts index 8e91775283042..fe46e5693bf45 100644 --- a/src/core/server/metrics/metrics_service.test.mocks.ts +++ b/src/core/server/metrics/metrics_service.test.mocks.ts @@ -17,9 +17,10 @@ * under the License. */ -export const mockOpsCollector = { - collect: jest.fn(), -}; +import { collectorMock } from './collectors/mocks'; + +export const mockOpsCollector = collectorMock.create(); + jest.doMock('./ops_metrics_collector', () => ({ OpsMetricsCollector: jest.fn().mockImplementation(() => mockOpsCollector), })); diff --git a/src/core/server/metrics/metrics_service.test.ts b/src/core/server/metrics/metrics_service.test.ts index 10d6761adbe7d..f6334cc5d3c0f 100644 --- a/src/core/server/metrics/metrics_service.test.ts +++ b/src/core/server/metrics/metrics_service.test.ts @@ -57,37 +57,50 @@ describe('MetricsService', () => { expect(setInterval).toHaveBeenCalledWith(expect.any(Function), testInterval); }); - it('emits the metrics at start', async () => { + it('collects the metrics at every interval', async () => { mockOpsCollector.collect.mockResolvedValue(dummyMetrics); - const { getOpsMetrics$ } = await metricsService.setup({ - http: httpMock, - }); - + await metricsService.setup({ http: httpMock }); await metricsService.start(); expect(mockOpsCollector.collect).toHaveBeenCalledTimes(1); - expect( - await getOpsMetrics$() - .pipe(take(1)) - .toPromise() - ).toEqual(dummyMetrics); + + jest.advanceTimersByTime(testInterval); + expect(mockOpsCollector.collect).toHaveBeenCalledTimes(2); + + jest.advanceTimersByTime(testInterval); + expect(mockOpsCollector.collect).toHaveBeenCalledTimes(3); }); - it('collects the metrics at every interval', async () => { + it('resets the collector after each collection', async () => { mockOpsCollector.collect.mockResolvedValue(dummyMetrics); - await metricsService.setup({ http: httpMock }); - + const { getOpsMetrics$ } = await metricsService.setup({ http: httpMock }); await metricsService.start(); + // `advanceTimersByTime` only ensure the interval handler is executed + // however the `reset` call is executed after the async call to `collect` + // meaning that we are going to miss the call if we don't wait for the + // actual observable emission that is performed after + const waitForNextEmission = () => + getOpsMetrics$() + .pipe(take(1)) + .toPromise(); + expect(mockOpsCollector.collect).toHaveBeenCalledTimes(1); + expect(mockOpsCollector.reset).toHaveBeenCalledTimes(1); + let nextEmission = waitForNextEmission(); jest.advanceTimersByTime(testInterval); + await nextEmission; expect(mockOpsCollector.collect).toHaveBeenCalledTimes(2); + expect(mockOpsCollector.reset).toHaveBeenCalledTimes(2); + nextEmission = waitForNextEmission(); jest.advanceTimersByTime(testInterval); + await nextEmission; expect(mockOpsCollector.collect).toHaveBeenCalledTimes(3); + expect(mockOpsCollector.reset).toHaveBeenCalledTimes(3); }); it('throws when called before setup', async () => { diff --git a/src/core/server/metrics/metrics_service.ts b/src/core/server/metrics/metrics_service.ts index 1aed89a4aad60..0ea9d00792600 100644 --- a/src/core/server/metrics/metrics_service.ts +++ b/src/core/server/metrics/metrics_service.ts @@ -17,8 +17,8 @@ * under the License. */ -import { ReplaySubject } from 'rxjs'; -import { first, shareReplay } from 'rxjs/operators'; +import { Subject } from 'rxjs'; +import { first } from 'rxjs/operators'; import { CoreService } from '../../types'; import { CoreContext } from '../core_context'; import { Logger } from '../logging'; @@ -37,7 +37,7 @@ export class MetricsService private readonly logger: Logger; private metricsCollector?: OpsMetricsCollector; private collectInterval?: NodeJS.Timeout; - private metrics$ = new ReplaySubject(1); + private metrics$ = new Subject(); constructor(private readonly coreContext: CoreContext) { this.logger = coreContext.logger.get('metrics'); @@ -46,7 +46,7 @@ export class MetricsService public async setup({ http }: MetricsServiceSetupDeps): Promise { this.metricsCollector = new OpsMetricsCollector(http.server); - const metricsObservable = this.metrics$.pipe(shareReplay(1)); + const metricsObservable = this.metrics$.asObservable(); return { getOpsMetrics$: () => metricsObservable, @@ -74,6 +74,7 @@ export class MetricsService private async refreshMetrics() { this.logger.debug('Refreshing metrics'); const metrics = await this.metricsCollector!.collect(); + this.metricsCollector!.reset(); this.metrics$.next(metrics); } diff --git a/src/core/server/metrics/ops_metrics_collector.test.mocks.ts b/src/core/server/metrics/ops_metrics_collector.test.mocks.ts index 8265796d57970..cf51f8a753729 100644 --- a/src/core/server/metrics/ops_metrics_collector.test.mocks.ts +++ b/src/core/server/metrics/ops_metrics_collector.test.mocks.ts @@ -17,23 +17,19 @@ * under the License. */ -export const mockOsCollector = { - collect: jest.fn(), -}; +import { collectorMock } from './collectors/mocks'; + +export const mockOsCollector = collectorMock.create(); jest.doMock('./collectors/os', () => ({ OsMetricsCollector: jest.fn().mockImplementation(() => mockOsCollector), })); -export const mockProcessCollector = { - collect: jest.fn(), -}; +export const mockProcessCollector = collectorMock.create(); jest.doMock('./collectors/process', () => ({ ProcessMetricsCollector: jest.fn().mockImplementation(() => mockProcessCollector), })); -export const mockServerCollector = { - collect: jest.fn(), -}; +export const mockServerCollector = collectorMock.create(); jest.doMock('./collectors/server', () => ({ ServerMetricsCollector: jest.fn().mockImplementation(() => mockServerCollector), })); diff --git a/src/core/server/metrics/ops_metrics_collector.test.ts b/src/core/server/metrics/ops_metrics_collector.test.ts index 04302a195fb6c..559588db60a42 100644 --- a/src/core/server/metrics/ops_metrics_collector.test.ts +++ b/src/core/server/metrics/ops_metrics_collector.test.ts @@ -35,25 +35,43 @@ describe('OpsMetricsCollector', () => { mockOsCollector.collect.mockResolvedValue('osMetrics'); }); - it('gathers metrics from the underlying collectors', async () => { - mockOsCollector.collect.mockResolvedValue('osMetrics'); - mockProcessCollector.collect.mockResolvedValue('processMetrics'); - mockServerCollector.collect.mockResolvedValue({ - requests: 'serverRequestsMetrics', - response_times: 'serverTimingMetrics', + describe('#collect', () => { + it('gathers metrics from the underlying collectors', async () => { + mockOsCollector.collect.mockResolvedValue('osMetrics'); + mockProcessCollector.collect.mockResolvedValue('processMetrics'); + mockServerCollector.collect.mockResolvedValue({ + requests: 'serverRequestsMetrics', + response_times: 'serverTimingMetrics', + }); + + const metrics = await collector.collect(); + + expect(mockOsCollector.collect).toHaveBeenCalledTimes(1); + expect(mockProcessCollector.collect).toHaveBeenCalledTimes(1); + expect(mockServerCollector.collect).toHaveBeenCalledTimes(1); + + expect(metrics).toEqual({ + process: 'processMetrics', + os: 'osMetrics', + requests: 'serverRequestsMetrics', + response_times: 'serverTimingMetrics', + }); }); + }); + + describe('#reset', () => { + it('call reset on the underlying collectors', () => { + collector.reset(); - const metrics = await collector.collect(); + expect(mockOsCollector.reset).toHaveBeenCalledTimes(1); + expect(mockProcessCollector.reset).toHaveBeenCalledTimes(1); + expect(mockServerCollector.reset).toHaveBeenCalledTimes(1); - expect(mockOsCollector.collect).toHaveBeenCalledTimes(1); - expect(mockProcessCollector.collect).toHaveBeenCalledTimes(1); - expect(mockServerCollector.collect).toHaveBeenCalledTimes(1); + collector.reset(); - expect(metrics).toEqual({ - process: 'processMetrics', - os: 'osMetrics', - requests: 'serverRequestsMetrics', - response_times: 'serverTimingMetrics', + expect(mockOsCollector.reset).toHaveBeenCalledTimes(2); + expect(mockProcessCollector.reset).toHaveBeenCalledTimes(2); + expect(mockServerCollector.reset).toHaveBeenCalledTimes(2); }); }); }); diff --git a/src/core/server/metrics/ops_metrics_collector.ts b/src/core/server/metrics/ops_metrics_collector.ts index 04344f21f57f7..525515dba1457 100644 --- a/src/core/server/metrics/ops_metrics_collector.ts +++ b/src/core/server/metrics/ops_metrics_collector.ts @@ -49,4 +49,10 @@ export class OpsMetricsCollector implements MetricsCollector { ...server, }; } + + public reset() { + this.processCollector.reset(); + this.osCollector.reset(); + this.serverCollector.reset(); + } } diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index 24dd1c4944bfb..bb954cb887ef3 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -38,7 +38,7 @@ import { } from '../../../../../../plugins/data/public'; import { buildTabularInspectorData } from './build_tabular_inspector_data'; -import { calculateObjectHash } from '../../../../visualizations/public'; +import { calculateObjectHash } from '../../../../../../plugins/kibana_utils/common'; import { tabifyAggResponse } from '../../../../../core_plugins/data/public'; import { PersistedState } from '../../../../../../plugins/visualizations/public'; import { Adapters } from '../../../../../../plugins/inspector/public'; diff --git a/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts b/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts index 1bdff06b3a59f..dae6c9abb625e 100644 --- a/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts +++ b/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts @@ -22,8 +22,9 @@ import { i18n } from '@kbn/i18n'; import { createInputControlVisController } from './vis_controller'; import { getControlsTab } from './components/editor/controls_tab'; import { OptionsTab } from './components/editor/options_tab'; -import { Status, defaultFeedbackMessage } from '../../visualizations/public'; +import { Status } from '../../visualizations/public'; import { InputControlVisDependencies } from './plugin'; +import { defaultFeedbackMessage } from '../../../../plugins/kibana_utils/common'; export function createInputControlVisTypeDefinition(deps: InputControlVisDependencies) { const InputControlVisController = createInputControlVisController(deps); diff --git a/src/legacy/core_plugins/input_control_vis/public/plugin.ts b/src/legacy/core_plugins/input_control_vis/public/plugin.ts index e9ffad8b35f21..e85ccd94f9e6a 100644 --- a/src/legacy/core_plugins/input_control_vis/public/plugin.ts +++ b/src/legacy/core_plugins/input_control_vis/public/plugin.ts @@ -59,7 +59,7 @@ export class InputControlVisPlugin implements Plugin, void> { }; expressions.registerFunction(createInputControlVisFn); - visualizations.types.createBaseVisualization( + visualizations.createBaseVisualization( createInputControlVisTypeDefinition(visualizationDependencies) ); } diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 91b5c7f13dc95..7fa5183a4f54b 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -50,7 +50,6 @@ export function setServices(newServices: any) { // EXPORT legacy static dependencies, should be migrated when available in a new version; export { angular }; export { wrapInI18nContext } from 'ui/i18n'; -export { buildVislibDimensions } from '../../../visualizations/public'; export { getRequestInspectorStats, getResponseInspectorStats } from '../../../data/public'; // @ts-ignore export { intervalOptions } from 'ui/agg_types'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index fb4158a6e3e03..81c10798936f5 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -45,7 +45,6 @@ import { getPainlessError } from './get_painless_error'; import { discoverResponseHandler } from './response_handler'; import { angular, - buildVislibDimensions, getRequestInspectorStats, getResponseInspectorStats, getServices, @@ -76,6 +75,7 @@ const { import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs'; import { esFilters, + fieldFormats, indexPatterns as indexPatternsUtils, } from '../../../../../../../plugins/data/public'; import { getIndexPatternId } from '../helpers/get_index_pattern_id'; @@ -812,21 +812,45 @@ function discoverController( $fetchObservable.next(); }; + function getDimensions(aggs, timeRange) { + const [metric, agg] = aggs; + agg.params.timeRange = timeRange; + const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null; + agg.buckets.setBounds(bounds); + + const { esUnit, esValue } = agg.buckets.getInterval(); + return { + x: { + accessor: 0, + label: agg.makeLabel(), + format: fieldFormats.serialize(agg), + params: { + date: true, + interval: moment.duration(esValue, esUnit), + intervalESValue: esValue, + intervalESUnit: esUnit, + format: agg.buckets.getScaledDateFormat(), + bounds: agg.buckets.getBounds(), + }, + }, + y: { + accessor: 1, + format: fieldFormats.serialize(metric), + label: metric.makeLabel(), + }, + }; + } + function onResults(resp) { logInspectorResponse(resp); if ($scope.opts.timefield) { const tabifiedData = tabifyAggResponse($scope.vis.aggs, resp); $scope.searchSource.rawResponse = resp; - Promise.resolve( - buildVislibDimensions($scope.vis, { - timefilter, - timeRange: $scope.timeRange, - searchSource: $scope.searchSource, - }) - ).then(resp => { - $scope.histogramData = discoverResponseHandler(tabifiedData, resp); - }); + $scope.histogramData = discoverResponseHandler( + tabifiedData, + getDimensions($scope.vis.aggs.aggs, $scope.timeRange) + ); } $scope.hits = resp.hits.total; @@ -993,7 +1017,7 @@ function discoverController( }, }; - $scope.vis = new visualizations.Vis( + $scope.vis = visualizations.createVis( $scope.searchSource.getField('index'), visSavedObject.visState ); diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts index 8dbf3cd79ccb1..7ea1863693e0d 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts @@ -29,7 +29,7 @@ import { getServices } from '../../../../kibana_services'; function getMapsAppBaseUrl() { const mapsAppVisAlias = getServices() - .visualizations.types.getAliases() + .visualizations.getAliases() .find(({ name }) => { return name === 'maps'; }); @@ -38,7 +38,7 @@ function getMapsAppBaseUrl() { export function isMapsAppRegistered() { return getServices() - .visualizations.types.getAliases() + .visualizations.getAliases() .some(({ name }) => { return name === 'maps'; }); diff --git a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts b/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts index 604575a6e6220..8e73a09480c41 100644 --- a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts +++ b/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { SavedObjectLoader } from '../../../../../plugins/saved_objects/public'; import { createSavedDashboardLoader } from '../dashboard'; -import { TypesService, createSavedVisLoader } from '../../../visualizations/public'; +import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy'; import { createSavedSearchesLoader } from '../../../../../plugins/discover/public'; /** @@ -58,10 +58,7 @@ const services = { savedObjectManagementRegistry.register({ id: 'savedVisualizations', - service: createSavedVisLoader({ - ...services, - ...{ visualizationTypes: new TypesService().start() }, - }), + service: visualizations.savedVisualizationsLoader, title: 'visualizations', }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts index cd7c8278adcc7..5a8460fcb51ba 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts @@ -19,7 +19,8 @@ import { getIndices } from './get_indices'; import { IndexPatternCreationConfig } from './../../../../../../../management/public'; -import { LegacyApiCaller } from '../../../../../../../../../plugins/data/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { LegacyApiCaller } from '../../../../../../../../../plugins/data/public/search'; export const successfulResponse = { hits: { diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index b8ee7cd378750..66a7bd6f33373 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -24,17 +24,8 @@ * directly where they are needed. */ -export { State } from 'ui/state_management/state'; -// @ts-ignore -export { GlobalStateProvider } from 'ui/state_management/global_state'; -// @ts-ignore -export { StateManagementConfigProvider } from 'ui/state_management/config_provider'; - export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; // @ts-ignore -export { EventsProvider } from 'ui/events'; -export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router'; -// @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts index b15d89275eba7..8ef63ec5778e2 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts @@ -23,13 +23,11 @@ import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext } from 'kibana/public'; import { configureAppAngularModule, - GlobalStateProvider, KbnUrlProvider, RedirectWhenMissingProvider, IPrivate, PrivateProvider, PromiseServiceCreator, - StateManagementConfigProvider, } from '../legacy_imports'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../../plugins/navigation/public'; import { @@ -87,35 +85,20 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav createLocalI18nModule(); createLocalPrivateModule(); createLocalPromiseModule(); - createLocalConfigModule(core); createLocalKbnUrlModule(); - createLocalStateModule(); createLocalTopNavModule(navigation); const visualizeAngularModule: IModule = angular.module(moduleName, [ ...thirdPartyAngularDependencies, - 'app/visualize/Config', 'app/visualize/I18n', 'app/visualize/Private', 'app/visualize/TopNav', - 'app/visualize/State', + 'app/visualize/KbnUrl', + 'app/visualize/Promise', ]); return visualizeAngularModule; } -function createLocalStateModule() { - angular - .module('app/visualize/State', [ - 'app/visualize/Private', - 'app/visualize/Config', - 'app/visualize/KbnUrl', - 'app/visualize/Promise', - ]) - .service('globalState', function(Private: IPrivate) { - return Private(GlobalStateProvider); - }); -} - function createLocalKbnUrlModule() { angular .module('app/visualize/KbnUrl', ['app/visualize/Private', 'ngRoute']) @@ -123,19 +106,6 @@ function createLocalKbnUrlModule() { .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider)); } -function createLocalConfigModule(core: AppMountContext['core']) { - angular - .module('app/visualize/Config', ['app/visualize/Private']) - .provider('stateManagementConfig', StateManagementConfigProvider) - .provider('config', () => { - return { - $get: () => ({ - get: core.uiSettings.get.bind(core.uiSettings), - }), - }; - }); -} - function createLocalPromiseModule() { angular.module('app/visualize/Promise', []).service('Promise', PromiseServiceCreator); } diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html index 9dbb05ea95b48..28baf21925cbe 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html @@ -31,8 +31,8 @@ refresh-interval="refreshInterval.value" on-refresh-change="onRefreshChange" show-save-query="showSaveQuery" - on-saved="onQuerySaved" - on-saved-query-updated="onSavedQueryUpdated" + on-saved="updateSavedQuery" + on-saved-query-updated="updateSavedQuery" on-clear-saved-query="onClearSavedQuery" > diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js index 2d2552b5e2f30..e1a20e3381331 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js @@ -20,6 +20,7 @@ import angular from 'angular'; import _ from 'lodash'; import { Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import React from 'react'; @@ -29,13 +30,17 @@ import { VisualizeConstants } from '../visualize_constants'; import { getEditBreadcrumbs } from '../breadcrumbs'; import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; -import { FilterStateManager } from '../../../../../data/public'; import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public'; import { kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public'; import { SavedObjectSaveModal, showSaveModal, } from '../../../../../../../plugins/saved_objects/public'; +import { + esFilters, + connectToQueryState, + syncQueryStateWithUrl, +} from '../../../../../../../plugins/data/public'; import { initVisEditorDirective } from './visualization_editor'; import { initVisualizationDirective } from './visualization'; @@ -65,28 +70,21 @@ export function initEditorDirective(app, deps) { function VisualizeAppController( $scope, - $element, $route, $window, $injector, $timeout, kbnUrl, redirectWhenMissing, - Promise, - globalState, - config + kbnUrlStateStorage, + history ) { const { indexPatterns, localStorage, visualizeCapabilities, share, - data: { - query: { - filterManager, - timefilter: { timefilter }, - }, - }, + data: { query: queryService }, toastNotifications, chrome, getBasePath, @@ -97,6 +95,17 @@ function VisualizeAppController( setActiveUrl, } = getServices(); + const { + filterManager, + timefilter: { timefilter }, + } = queryService; + + // starts syncing `_g` portion of url with query services + const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl( + queryService, + kbnUrlStateStorage + ); + // Retrieve the resolved SavedVis instance. const savedVis = $route.current.locals.savedVis; const _applyVis = () => { @@ -284,26 +293,24 @@ function VisualizeAppController( linked: !!savedVis.savedSearchId, }; - const useHash = config.get('state:storeInSessionStorage'); const { stateContainer, stopStateSync } = useVisualizeAppState({ - useHash, stateDefaults, + kbnUrlStateStorage, }); - const filterStateManager = new FilterStateManager( - globalState, - () => { - // Temporary AppState replacement - return { - set filters(_filters) { - stateContainer.transitions.set('filters', _filters); - }, - get filters() { - return stateContainer.getState().filters; - }, - }; + // sync initial app filters from state to filterManager + filterManager.setAppFilters(_.cloneDeep(stateContainer.getState().filters)); + // setup syncing of app filters between appState and filterManager + const stopSyncingAppFilters = connectToQueryState( + queryService, + { + set: ({ filters }) => stateContainer.transitions.set('filters', filters), + get: () => ({ filters: stateContainer.getState().filters }), + state$: stateContainer.state$.pipe(map(state => ({ filters: state.filters }))), }, - filterManager + { + filters: esFilters.FilterStateStore.APP_STATE, + } ); // The savedVis is pulled from elasticsearch, but the appState is pulled from the url, with the @@ -335,6 +342,24 @@ function VisualizeAppController( } ); + const updateSavedQueryFromUrl = savedQueryId => { + if (!savedQueryId) { + delete $scope.savedQuery; + + return; + } + + if ($scope.savedQuery && $scope.savedQuery.id === savedQueryId) { + return; + } + + savedQueryService.getSavedQuery(savedQueryId).then(savedQuery => { + $scope.$evalAsync(() => { + $scope.updateSavedQuery(savedQuery); + }); + }); + }; + function init() { if (vis.indexPattern) { $scope.indexPattern = vis.indexPattern; @@ -388,7 +413,6 @@ function VisualizeAppController( }; $scope.timeRange = timefilter.getTime(); - $scope.opts = _.pick($scope, 'savedVis', 'isAddToDashMode'); const unsubscribeStateUpdates = stateContainer.subscribe(state => { const newQuery = migrateLegacyQuery(state.query); @@ -396,6 +420,7 @@ function VisualizeAppController( stateContainer.transitions.set('query', newQuery); } persistOnChange(state); + updateSavedQueryFromUrl(state.savedQuery); // if the browser history was changed manually we need to reflect changes in the editor if (!_.isEqual(vis.getState(), state.vis)) { @@ -413,6 +438,9 @@ function VisualizeAppController( $scope.$broadcast('render'); }; + // update the query if savedQuery is stored + updateSavedQueryFromUrl(initialState.savedQuery); + const subscriptions = new Subscription(); subscriptions.add( @@ -438,7 +466,7 @@ function VisualizeAppController( // update the searchSource when query updates $scope.fetch = function() { - const { query, filters, linked } = stateContainer.getState(); + const { query, linked, filters } = stateContainer.getState(); $scope.query = query; $scope.linked = linked; savedVis.searchSource.setField('query', query); @@ -451,7 +479,6 @@ function VisualizeAppController( subscribeWithScope($scope, filterManager.getUpdates$(), { next: () => { $scope.filters = filterManager.getFilters(); - $scope.globalFilters = filterManager.getGlobalFilters(); }, }) ); @@ -466,13 +493,14 @@ function VisualizeAppController( $scope._handler.destroy(); } savedVis.destroy(); - filterStateManager.destroy(); subscriptions.unsubscribe(); $scope.vis.off('apply', _applyVis); unsubscribePersisted(); unsubscribeStateUpdates(); stopStateSync(); + stopSyncingQueryServiceStateWithUrl(); + stopSyncingAppFilters(); }); $timeout(() => { @@ -501,23 +529,14 @@ function VisualizeAppController( }); }; - $scope.onQuerySaved = savedQuery => { - $scope.savedQuery = savedQuery; - }; - - $scope.onSavedQueryUpdated = savedQuery => { - $scope.savedQuery = { ...savedQuery }; - }; - $scope.onClearSavedQuery = () => { delete $scope.savedQuery; stateContainer.transitions.removeSavedQuery(defaultQuery); filterManager.setFilters(filterManager.getGlobalFilters()); - $scope.fetch(); }; const updateStateFromSavedQuery = savedQuery => { - stateContainer.transitions.set('query', savedQuery.attributes.query); + stateContainer.transitions.updateFromSavedQuery(savedQuery); const savedQueryFilters = savedQuery.attributes.filters || []; const globalFilters = filterManager.getGlobalFilters(); @@ -532,25 +551,12 @@ function VisualizeAppController( timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval); } } - - $scope.fetch(); }; - // update the query if savedQuery is stored - if (stateContainer.getState().savedQuery) { - savedQueryService.getSavedQuery(stateContainer.getState().savedQuery).then(savedQuery => { - $scope.$evalAsync(() => { - $scope.savedQuery = savedQuery; - }); - }); - } - - $scope.$watch('savedQuery', newSavedQuery => { - if (!newSavedQuery) return; - stateContainer.transitions.set('savedQuery', newSavedQuery.id); - - updateStateFromSavedQuery(newSavedQuery); - }); + $scope.updateSavedQuery = savedQuery => { + $scope.savedQuery = savedQuery; + updateStateFromSavedQuery(savedQuery); + }; $scope.$watch('linked', linked => { if (linked && !savedVis.savedSearchId) { @@ -626,7 +632,10 @@ function VisualizeAppController( savedVis.vis.title = savedVis.title; savedVis.vis.description = savedVis.description; } else { - kbnUrl.change(`${VisualizeConstants.EDIT_PATH}/{{id}}`, { id: savedVis.id }); + history.replace({ + ...history.location, + pathname: `${VisualizeConstants.EDIT_PATH}/${savedVis.id}`, + }); } } }); diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/lib/visualize_app_state.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/lib/visualize_app_state.ts index d8de81193d857..d3fae3d457b63 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/lib/visualize_app_state.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/lib/visualize_app_state.ts @@ -17,21 +17,20 @@ * under the License. */ -import { createHashHistory } from 'history'; import { isFunction, omit } from 'lodash'; import { migrateAppState } from './migrate_app_state'; import { - createKbnUrlStateStorage, createStateContainer, syncState, + IKbnUrlStateStorage, } from '../../../../../../../../plugins/kibana_utils/public'; import { PureVisState, VisualizeAppState, VisualizeAppStateTransitions } from '../../types'; const STATE_STORAGE_KEY = '_a'; interface Arguments { - useHash: boolean; + kbnUrlStateStorage: IKbnUrlStateStorage; stateDefaults: VisualizeAppState; } @@ -41,12 +40,7 @@ function toObject(state: PureVisState): PureVisState { }); } -export function useVisualizeAppState({ useHash, stateDefaults }: Arguments) { - const history = createHashHistory(); - const kbnUrlStateStorage = createKbnUrlStateStorage({ - useHash, - history, - }); +export function useVisualizeAppState({ stateDefaults, kbnUrlStateStorage }: Arguments) { const urlState = kbnUrlStateStorage.get(STATE_STORAGE_KEY); const initialState = migrateAppState({ ...stateDefaults, @@ -88,6 +82,11 @@ export function useVisualizeAppState({ useHash, stateDefaults }: Arguments) { linked: false, }), updateVisState: state => newVisState => ({ ...state, vis: toObject(newVisState) }), + updateFromSavedQuery: state => savedQuery => ({ + ...state, + savedQuery: savedQuery.id, + query: savedQuery.attributes.query, + }), } ); diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/global_state_sync.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/global_state_sync.ts deleted file mode 100644 index f29fb72a9fbc5..0000000000000 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/global_state_sync.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { State } from '../legacy_imports'; -import { DataPublicPluginStart as DataStart } from '../../../../../../plugins/data/public'; - -/** - * Helper function to sync the global state with the various state providers - * when a local angular application mounts. There are three different ways - * global state can be passed into the application: - * * parameter in the URL hash - e.g. shared link - * * in-memory state in the data plugin exports (timefilter and filterManager) - e.g. default values - * - * This function looks up the three sources (earlier in the list means it takes precedence), - * puts it into the globalState object and syncs it with the url. - * - * Currently the legacy chrome takes care of restoring the global state when navigating from - * one app to another - to migrate away from that it will become necessary to also write the current - * state to local storage - */ -export function syncOnMount( - globalState: State, - { - query: { - filterManager, - timefilter: { timefilter }, - }, - }: DataStart -) { - // pull in global state information from the URL - globalState.fetch(); - // remember whether there were info in the URL - const hasGlobalURLState = Boolean(Object.keys(globalState.toObject()).length); - - // sync kibana platform state with the angular global state - if (!globalState.time) { - globalState.time = timefilter.getTime(); - } - if (!globalState.refreshInterval) { - globalState.refreshInterval = timefilter.getRefreshInterval(); - } - if (!globalState.filters && filterManager.getGlobalFilters().length > 0) { - globalState.filters = filterManager.getGlobalFilters(); - } - // only inject cross app global state if there is none in the url itself (that takes precedence) - if (hasGlobalURLState) { - // set flag the global state is set from the URL - globalState.$inheritedGlobalState = true; - } - globalState.save(); -} diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js index 24055b9a2d9ed..b9409445166bc 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js @@ -19,6 +19,9 @@ import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { createHashHistory } from 'history'; + +import { createKbnUrlStateStorage } from '../../../../../../plugins/kibana_utils/public'; import editorTemplate from './editor/editor.html'; import visualizeListingTemplate from './listing/visualize_listing.html'; @@ -26,11 +29,7 @@ import visualizeListingTemplate from './listing/visualize_listing.html'; import { initVisualizeAppDirective } from './visualize_app'; import { VisualizeConstants } from './visualize_constants'; import { VisualizeListingController } from './listing/visualize_listing'; -import { - ensureDefaultIndexPattern, - registerTimefilterWithGlobalStateFactory, -} from '../legacy_imports'; -import { syncOnMount } from './global_state_sync'; +import { ensureDefaultIndexPattern } from '../legacy_imports'; import { getLandingBreadcrumbs, @@ -42,17 +41,13 @@ import { export function initVisualizeApp(app, deps) { initVisualizeAppDirective(app, deps); - app.run(globalState => { - syncOnMount(globalState, deps.data); - }); - - app.run((globalState, $rootScope) => { - registerTimefilterWithGlobalStateFactory( - deps.data.query.timefilter.timefilter, - globalState, - $rootScope - ); - }); + app.factory('history', () => createHashHistory()); + app.factory('kbnUrlStateStorage', history => + createKbnUrlStateStorage({ + history, + useHash: deps.uiSettings.get('state:storeInSessionStorage'), + }) + ); app.config(function($routeProvider) { const defaults = { @@ -107,7 +102,7 @@ export function initVisualizeApp(app, deps) { resolve: { savedVis: function(redirectWhenMissing, $route, $rootScope, kbnUrl) { const { core, data, savedVisualizations, visualizations } = deps; - const visTypes = visualizations.types.all(); + const visTypes = visualizations.all(); const visType = find(visTypes, { name: $route.current.params.type }); const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection; const hasIndex = diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js index c0cc499b598f0..5a479a491395a 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js @@ -26,23 +26,21 @@ import { i18n } from '@kbn/i18n'; import { getServices } from '../../kibana_services'; import { wrapInI18nContext } from '../../legacy_imports'; +import { syncQueryStateWithUrl } from '../../../../../../../plugins/data/public'; + export function initListingDirective(app) { app.directive('visualizeListingTable', reactDirective => reactDirective(wrapInI18nContext(VisualizeListingTable)) ); } -export function VisualizeListingController($injector, $scope, createNewVis) { +export function VisualizeListingController($injector, $scope, createNewVis, kbnUrlStateStorage) { const { addBasePath, chrome, savedObjectsClient, savedVisualizations, - data: { - query: { - timefilter: { timefilter }, - }, - }, + data: { query }, toastNotifications, uiSettings, visualizations, @@ -50,6 +48,16 @@ export function VisualizeListingController($injector, $scope, createNewVis) { } = getServices(); const kbnUrl = $injector.get('kbnUrl'); + // syncs `_g` portion of url with query services + const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl( + query, + kbnUrlStateStorage + ); + + const { + timefilter: { timefilter }, + } = query; + timefilter.disableAutoRefreshSelector(); timefilter.disableTimeRangeSelector(); @@ -124,5 +132,7 @@ export function VisualizeListingController($injector, $scope, createNewVis) { if (this.closeNewVisModal) { this.closeNewVisModal(); } + + stopSyncingQueryServiceStateWithUrl(); }); } diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts index 8ca603eb11459..55fccd75361a0 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts @@ -17,7 +17,13 @@ * under the License. */ -import { TimeRange, Query, Filter, DataPublicPluginStart } from 'src/plugins/data/public'; +import { + TimeRange, + Query, + Filter, + DataPublicPluginStart, + SavedQuery, +} from 'src/plugins/data/public'; import { IEmbeddableStart } from 'src/plugins/embeddable/public'; import { PersistedState } from 'src/plugins/visualizations/public'; import { LegacyCoreStart } from 'kibana/public'; @@ -48,6 +54,7 @@ export interface VisualizeAppStateTransitions { state: VisualizeAppState ) => (query: Query, filters: Filter[]) => VisualizeAppState; updateVisState: (state: VisualizeAppState) => (vis: PureVisState) => VisualizeAppState; + updateFromSavedQuery: (state: VisualizeAppState) => (savedQuery: SavedQuery) => VisualizeAppState; } export interface EditorRenderProps { diff --git a/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js b/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js index f11aab9b9db88..6bdb5d00e67d8 100644 --- a/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js +++ b/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js @@ -111,9 +111,7 @@ describe('RegionMapsVisualizationTests', function() { if (!visRegComplete) { visRegComplete = true; - visualizationsSetup.types.createBaseVisualization( - createRegionMapTypeDefinition(dependencies) - ); + visualizationsSetup.createBaseVisualization(createRegionMapTypeDefinition(dependencies)); } RegionMapsVisualization = createRegionMapVisualization(dependencies); @@ -160,7 +158,7 @@ describe('RegionMapsVisualizationTests', function() { imageComparator = new ImageComparator(); - vis = new visualizationsStart.Vis(indexPattern, { + vis = visualizationsStart.createVis(indexPattern, { type: 'region_map', }); diff --git a/src/legacy/core_plugins/region_map/public/plugin.ts b/src/legacy/core_plugins/region_map/public/plugin.ts index aaf0a8a308aea..98fb5604c3d65 100644 --- a/src/legacy/core_plugins/region_map/public/plugin.ts +++ b/src/legacy/core_plugins/region_map/public/plugin.ts @@ -70,7 +70,7 @@ export class RegionMapPlugin implements Plugin, void> { expressions.registerFunction(createRegionMapFn); - visualizations.types.createBaseVisualization( + visualizations.createBaseVisualization( createRegionMapTypeDefinition(visualizationDependencies) ); } diff --git a/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js index 27e9459c7e06c..6a08405b5b6a5 100644 --- a/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js @@ -88,9 +88,7 @@ describe('CoordinateMapsVisualizationTest', function() { if (!visRegComplete) { visRegComplete = true; - visualizationsSetup.types.createBaseVisualization( - createTileMapTypeDefinition(dependencies) - ); + visualizationsSetup.createBaseVisualization(createTileMapTypeDefinition(dependencies)); } CoordinateMapsVisualization = createTileMapVisualization(dependencies); @@ -126,7 +124,7 @@ describe('CoordinateMapsVisualizationTest', function() { setupDOM('512px', '512px'); imageComparator = new ImageComparator(); - vis = new visualizationsStart.Vis(indexPattern, { + vis = visualizationsStart.createVis(indexPattern, { type: 'tile_map', }); vis.params = { diff --git a/src/legacy/core_plugins/tile_map/public/plugin.ts b/src/legacy/core_plugins/tile_map/public/plugin.ts index 52acaf51b39b1..a12c2753cc525 100644 --- a/src/legacy/core_plugins/tile_map/public/plugin.ts +++ b/src/legacy/core_plugins/tile_map/public/plugin.ts @@ -64,9 +64,7 @@ export class TileMapPlugin implements Plugin, void> { expressions.registerFunction(() => createTileMapFn(visualizationDependencies)); - visualizations.types.createBaseVisualization( - createTileMapTypeDefinition(visualizationDependencies) - ); + visualizations.createBaseVisualization(createTileMapTypeDefinition(visualizationDependencies)); } public start(core: CoreStart) { diff --git a/src/legacy/core_plugins/timelion/public/app.js b/src/legacy/core_plugins/timelion/public/app.js index e4a48c09db832..a9d678cfea79c 100644 --- a/src/legacy/core_plugins/timelion/public/app.js +++ b/src/legacy/core_plugins/timelion/public/app.js @@ -42,7 +42,7 @@ import '../../data/public/legacy'; import './services/saved_sheet_register'; import rootTemplate from 'plugins/timelion/index.html'; -import { createSavedVisLoader, TypesService } from '../../visualizations/public'; +import { start as visualizations } from '../../visualizations/public/np_ready/public/legacy'; import { loadKbnTopNavDirectives } from '../../../../plugins/kibana_legacy/public'; loadKbnTopNavDirectives(npStart.plugins.navigation.ui); @@ -127,13 +127,7 @@ app.controller('timelion', function( timefilter.enableAutoRefreshSelector(); timefilter.enableTimeRangeSelector(); - const savedVisualizations = createSavedVisLoader({ - savedObjectsClient: npStart.core.savedObjects.client, - indexPatterns: npStart.plugins.data.indexPatterns, - chrome: npStart.core.chrome, - overlays: npStart.core.overlays, - visualizationTypes: new TypesService().start(), - }); + const savedVisualizations = visualizations.savedVisualizationsLoader; const timezone = Private(timezoneProvider)(); const defaultExpression = '.es(*)'; diff --git a/src/legacy/core_plugins/vis_type_markdown/public/plugin.ts b/src/legacy/core_plugins/vis_type_markdown/public/plugin.ts index f131664756202..71d6c1c69ef2d 100644 --- a/src/legacy/core_plugins/vis_type_markdown/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_markdown/public/plugin.ts @@ -39,7 +39,7 @@ export class MarkdownPlugin implements Plugin { } public setup(core: CoreSetup, { expressions, visualizations }: MarkdownPluginSetupDependencies) { - visualizations.types.createReactVisualization(markdownVisDefinition); + visualizations.createReactVisualization(markdownVisDefinition); expressions.registerFunction(createMarkdownVisFn); } diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index 67b5d018f4638..5dbd59f3f1709 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -40,7 +40,7 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { let vis: Vis; beforeAll(() => { - visualizationsSetup.types.createReactVisualization(createMetricVisTypeDefinition()); + visualizationsSetup.createReactVisualization(createMetricVisTypeDefinition()); (npStart.plugins.data.fieldFormats.getType as jest.Mock).mockImplementation(() => { return fieldFormats.UrlFormat; }); @@ -59,7 +59,7 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { // TODO: remove when Vis is converted to typescript. Only importing Vis as type // @ts-ignore - vis = new visualizationsStart.Vis(stubIndexPattern, { + vis = visualizationsStart.createVis(stubIndexPattern, { type: 'metric', aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }], }); @@ -80,7 +80,7 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { }; const el = document.createElement('div'); - const metricVisType = visualizationsStart.types.get('metric'); + const metricVisType = visualizationsStart.get('metric'); const Controller = metricVisType.visualization; const controller = new Controller(el, vis); const render = (esResponse: any) => { diff --git a/src/legacy/core_plugins/vis_type_metric/public/plugin.ts b/src/legacy/core_plugins/vis_type_metric/public/plugin.ts index 082fab47e573c..28b435cbc7980 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/plugin.ts @@ -45,7 +45,7 @@ export class MetricVisPlugin implements Plugin { { expressions, visualizations, charts }: MetricVisPluginSetupDependencies ) { expressions.registerFunction(createMetricVisFn); - visualizations.types.createReactVisualization(createMetricVisTypeDefinition()); + visualizations.createReactVisualization(createMetricVisTypeDefinition()); } public start(core: CoreStart) { diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js index 9fe7920588cd2..91581923b05cb 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js +++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js @@ -47,10 +47,10 @@ describe('Table Vis - AggTable Directive', function() { const tabifiedData = {}; const init = () => { - const vis1 = new visualizationsStart.Vis(indexPattern, 'table'); + const vis1 = visualizationsStart.createVis(indexPattern, 'table'); tabifiedData.metricOnly = tabifyAggResponse(vis1.aggs, metricOnly); - const vis2 = new visualizationsStart.Vis(indexPattern, { + const vis2 = visualizationsStart.createVis(indexPattern, { type: 'table', params: { showMetricsAtAllLevels: true, @@ -69,7 +69,7 @@ describe('Table Vis - AggTable Directive', function() { metricsAtAllLevels: true, }); - const vis3 = new visualizationsStart.Vis(indexPattern, { + const vis3 = visualizationsStart.createVis(indexPattern, { type: 'table', aggs: [ { type: 'avg', schema: 'metric', params: { field: 'bytes' } }, @@ -110,7 +110,7 @@ describe('Table Vis - AggTable Directive', function() { beforeEach(initLocalAngular); ngMock.inject(function() { - visualizationsSetup.types.createBaseVisualization(tableVisTypeDefinition); + visualizationsSetup.createBaseVisualization(tableVisTypeDefinition); }); beforeEach(ngMock.module('kibana/table_vis')); diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js index 79d4d7c40d355..4d62551dcf396 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js +++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js @@ -35,10 +35,10 @@ describe('Table Vis - AggTableGroup Directive', function() { const tabifiedData = {}; const init = () => { - const vis1 = new visualizationsStart.Vis(indexPattern, 'table'); + const vis1 = visualizationsStart.createVis(indexPattern, 'table'); tabifiedData.metricOnly = tabifyAggResponse(vis1.aggs, metricOnly); - const vis2 = new visualizationsStart.Vis(indexPattern, { + const vis2 = visualizationsStart.createVis(indexPattern, { type: 'pie', aggs: [ { type: 'avg', schema: 'metric', params: { field: 'bytes' } }, diff --git a/src/legacy/core_plugins/vis_type_table/public/plugin.ts b/src/legacy/core_plugins/vis_type_table/public/plugin.ts index 17c50b0567b67..519a56da23ac9 100644 --- a/src/legacy/core_plugins/vis_type_table/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_table/public/plugin.ts @@ -44,7 +44,7 @@ export class TableVisPlugin implements Plugin, void> { ) { expressions.registerFunction(createTableVisFn); - visualizations.types.createBaseVisualization(tableVisTypeDefinition); + visualizations.createBaseVisualization(tableVisTypeDefinition); } public start(core: CoreStart) { diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js index 55ecf98f994d2..3091b3340cd6d 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud_visualization.js @@ -76,7 +76,7 @@ describe('TagCloudVisualizationTest', function() { beforeEach(async function() { setupDOM('512px', '512px'); imageComparator = new ImageComparator(); - vis = new visualizationsStart.Vis(indexPattern, { + vis = visualizationsStart.createVis(indexPattern, { type: 'tagcloud', params: { bucket: { accessor: 0, format: {} }, diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/plugin.ts b/src/legacy/core_plugins/vis_type_tagcloud/public/plugin.ts index 9e5940eca1598..8244cba38edc3 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/plugin.ts @@ -53,7 +53,7 @@ export class TagCloudPlugin implements Plugin { colors: charts.colors, }; expressions.registerFunction(createTagCloudFn); - visualizations.types.createBaseVisualization( + visualizations.createBaseVisualization( createTagCloudVisTypeDefinition(visualizationDependencies) ); } diff --git a/src/legacy/core_plugins/vis_type_timelion/public/plugin.ts b/src/legacy/core_plugins/vis_type_timelion/public/plugin.ts index 69a2ad3c1351a..9d69c312b48f4 100644 --- a/src/legacy/core_plugins/vis_type_timelion/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_timelion/public/plugin.ts @@ -66,7 +66,7 @@ export class TimelionVisPlugin implements Plugin { }; expressions.registerFunction(() => getTimelionVisualizationConfig(dependencies)); - visualizations.types.createReactVisualization(getTimelionVisDefinition(dependencies)); + visualizations.createReactVisualization(getTimelionVisDefinition(dependencies)); } public start(core: CoreStart, plugins: PluginsStart) { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts index 135cc1e181432..30c62d778933b 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts @@ -25,7 +25,7 @@ import { metricsRequestHandler } from './request_handler'; import { EditorController } from './editor_controller'; // @ts-ignore import { PANEL_TYPES } from '../../../../plugins/vis_type_timeseries/common/panel_types'; -import { defaultFeedbackMessage } from '../../visualizations/public'; +import { defaultFeedbackMessage } from '../../../../plugins/kibana_utils/common'; export const metricsVisDefinition = { name: 'metrics', diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts b/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts index 38a9c68487854..441b1f05ea78c 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts @@ -57,7 +57,7 @@ export class MetricsPlugin implements Plugin, void> { ) { expressions.registerFunction(createMetricsFn); setUISettings(core.uiSettings); - visualizations.types.createReactVisualization(metricsVisDefinition); + visualizations.createReactVisualization(metricsVisDefinition); } public start(core: CoreStart, { data }: MetricsPluginStartDependencies) { diff --git a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js index 378590af29d3a..5befc09b24544 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js +++ b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js @@ -93,7 +93,7 @@ describe('VegaVisualizations', () => { if (!visRegComplete) { visRegComplete = true; - visualizationsSetup.types.createBaseVisualization( + visualizationsSetup.createBaseVisualization( createVegaTypeDefinition(vegaVisualizationDependencies) ); } @@ -108,7 +108,7 @@ describe('VegaVisualizations', () => { setupDOM('512px', '512px'); imageComparator = new ImageComparator(); - vis = new visualizationsStart.Vis(indexPattern, { type: 'vega' }); + vis = visualizationsStart.createVis(indexPattern, { type: 'vega' }); }); afterEach(function() { diff --git a/src/legacy/core_plugins/vis_type_vega/public/plugin.ts b/src/legacy/core_plugins/vis_type_vega/public/plugin.ts index b354433330caf..3b01d9ceca5a6 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/plugin.ts @@ -84,9 +84,7 @@ export class VegaPlugin implements Plugin, void> { expressions.registerFunction(() => createVegaFn(visualizationDependencies)); - visualizations.types.createBaseVisualization( - createVegaTypeDefinition(visualizationDependencies) - ); + visualizations.createBaseVisualization(createVegaTypeDefinition(visualizationDependencies)); } public start(core: CoreStart, { data }: VegaPluginStartDependencies) { diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts b/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts index a84948f725e0a..78f9c170ab62d 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts @@ -19,10 +19,11 @@ import { i18n } from '@kbn/i18n'; // @ts-ignore -import { Status, defaultFeedbackMessage } from '../../visualizations/public'; +import { Status } from '../../visualizations/public'; import { DefaultEditorSize } from '../../vis_default_editor/public'; import { VegaVisualizationDependencies } from './plugin'; import { VegaVisEditor } from './components'; +import { defaultFeedbackMessage } from '../../../../plugins/kibana_utils/common'; import { createVegaRequestHandler } from './vega_request_handler'; // @ts-ignore diff --git a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts index 8a7196a61ecec..a71892cc47b05 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts @@ -97,14 +97,14 @@ export class VisTypeVislibPlugin implements Plugin, void> { // Register legacy vislib types that have been converted convertedFns.forEach(expressions.registerFunction); convertedTypes.forEach(vis => - visualizations.types.createBaseVisualization(vis(visualizationDependencies)) + visualizations.createBaseVisualization(vis(visualizationDependencies)) ); } // Register non-converted types vislibFns.forEach(expressions.registerFunction); vislibTypes.forEach(vis => - visualizations.types.createBaseVisualization(vis(visualizationDependencies)) + visualizations.createBaseVisualization(vis(visualizationDependencies)) ); } diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js index 9c9c5a84f046c..43e3b987f1962 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/visualizations/pie_chart.js @@ -133,7 +133,7 @@ describe('No global chart settings', function() { responseHandler = vislibSlicesResponseHandler; let id1 = 1; - stubVis1 = new visualizationsStart.Vis(indexPattern, { + stubVis1 = visualizationsStart.createVis(indexPattern, { type: 'pie', aggs: rowAgg, }); @@ -222,7 +222,7 @@ describe('Vislib PieChart Class Test Suite', function() { responseHandler = vislibSlicesResponseHandler; let id = 1; - stubVis = new visualizationsStart.Vis(indexPattern, { + stubVis = visualizationsStart.createVis(indexPattern, { type: 'pie', aggs: dataAgg, }); diff --git a/src/legacy/core_plugins/vis_type_xy/public/plugin.ts b/src/legacy/core_plugins/vis_type_xy/public/plugin.ts index 59bb64b337256..35abb04fd8732 100644 --- a/src/legacy/core_plugins/vis_type_xy/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_xy/public/plugin.ts @@ -72,7 +72,7 @@ export class VisTypeXyPlugin implements Plugin, void> { visFunctions.forEach((fn: any) => expressions.registerFunction(fn)); visTypeDefinitions.forEach((vis: any) => - visualizations.types.createBaseVisualization(vis(visualizationDependencies)) + visualizations.createBaseVisualization(vis(visualizationDependencies)) ); } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts index 7688a7769cf79..b59eb2277411c 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts @@ -43,20 +43,11 @@ export { Vis, VisParams, VisState } from './vis'; import { VisualizeEmbeddableFactory, VisualizeEmbeddable } from './embeddable'; export type VisualizeEmbeddableFactoryContract = PublicContract; export type VisualizeEmbeddableContract = PublicContract; +export { TypesService } from './vis_types/types_service'; +export { Status } from './legacy/update_status'; // should remove +export { VISUALIZE_EMBEDDABLE_TYPE, VisualizeInput } from './embeddable'; +export { SchemaConfig } from './legacy/build_pipeline'; export function plugin(initializerContext: PluginInitializerContext) { return new VisualizationsPlugin(initializerContext); } - -/** @public static code */ -export { TypesService } from './vis_types/types_service'; -export { VISUALIZE_EMBEDDABLE_TYPE, VisualizeInput } from './embeddable'; - -export { Status } from './legacy/update_status'; -export { buildPipeline, buildVislibDimensions, SchemaConfig } from './legacy/build_pipeline'; - -// @ts-ignore -export { updateOldState } from './legacy/vis_update_state'; -export { calculateObjectHash } from './legacy/calculate_object_hash'; -export { createSavedVisLoader } from './saved_visualizations/saved_visualizations'; -export { defaultFeedbackMessage } from './misc/default_feedback_message'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js index 8c75ba24051b0..deb345a77cdb6 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/_vis.js @@ -43,12 +43,12 @@ describe('Vis Class', function() { beforeEach( ngMock.inject(function(Private) { indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - visTypes = visualizations.types; + visTypes = visualizations; }) ); beforeEach(function() { - vis = new visualizations.Vis(indexPattern, stateFixture); + vis = visualizations.createVis(indexPattern, stateFixture); }); const verifyVis = function(vis) { @@ -84,7 +84,7 @@ describe('Vis Class', function() { describe('setState()', function() { it('should set the state to defaults', function() { - const vis = new visualizations.Vis(indexPattern); + const vis = visualizations.createVis(indexPattern); expect(vis).to.have.property('type'); expect(vis.type).to.eql(visTypes.get('histogram')); expect(vis).to.have.property('aggs'); @@ -100,7 +100,7 @@ describe('Vis Class', function() { expect(vis.isHierarchical()).to.be(true); }); it('should return false for non-hierarchical vis (like histogram)', function() { - const vis = new visualizations.Vis(indexPattern); + const vis = visualizations.createVis(indexPattern); expect(vis.isHierarchical()).to.be(false); }); }); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts index d9af5122eadec..92a9ce8366f4f 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts @@ -18,7 +18,7 @@ */ import { PersistedState } from '../../../../../../../plugins/visualizations/public'; -import { calculateObjectHash } from './calculate_object_hash'; +import { calculateObjectHash } from '../../../../../../../plugins/kibana_utils/common'; import { Vis } from '../vis'; enum Status { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts index 8d7407b6191d6..9e8eac08c33ea 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts @@ -28,23 +28,19 @@ import { usageCollectionPluginMock } from '../../../../../../plugins/usage_colle import { uiActionsPluginMock } from '../../../../../../plugins/ui_actions/public/mocks'; const createSetupContract = (): VisualizationsSetup => ({ - types: { - createBaseVisualization: jest.fn(), - createReactVisualization: jest.fn(), - registerAlias: jest.fn(), - hideTypes: jest.fn(), - }, + createBaseVisualization: jest.fn(), + createReactVisualization: jest.fn(), + registerAlias: jest.fn(), + hideTypes: jest.fn(), }); const createStartContract = (): VisualizationsStart => ({ - types: { - get: jest.fn(), - all: jest.fn(), - getAliases: jest.fn(), - }, + get: jest.fn(), + all: jest.fn(), + getAliases: jest.fn(), savedVisualizationsLoader: {} as any, showNewVisModal: jest.fn(), - Vis: jest.fn(), + createVis: jest.fn(), }); const createInstance = async () => { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts index 10797a1a04df4..b8db611f30815 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts @@ -48,27 +48,27 @@ import { visualization as visualizationRenderer } from './expressions/visualizat import { DataPublicPluginSetup, DataPublicPluginStart, + IIndexPattern, } from '../../../../../../plugins/data/public'; import { UsageCollectionSetup } from '../../../../../../plugins/usage_collection/public'; import { createSavedVisLoader, SavedVisualizationsLoader } from './saved_visualizations'; -import { VisImpl, VisImplConstructor } from './vis_impl'; +import { VisImpl } from './vis_impl'; import { showNewVisModal } from './wizard'; import { UiActionsStart } from '../../../../../../plugins/ui_actions/public'; import { DataStart as LegacyDataStart } from '../../../../data/public'; +import { VisState } from './types'; /** * Interface for this plugin's returned setup/start contracts. * * @public */ -export interface VisualizationsSetup { - types: TypesSetup; -} -export interface VisualizationsStart { - types: TypesStart; +export type VisualizationsSetup = TypesSetup; + +export interface VisualizationsStart extends TypesStart { savedVisualizationsLoader: SavedVisualizationsLoader; - Vis: VisImplConstructor; + createVis: (indexPattern: IIndexPattern, visState?: VisState) => VisImpl; showNewVisModal: typeof showNewVisModal; } @@ -122,7 +122,7 @@ export class VisualizationsPlugin embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory); return { - types: this.types.setup(), + ...this.types.setup(), }; } @@ -152,9 +152,15 @@ export class VisualizationsPlugin setSavedVisualizationsLoader(savedVisualizationsLoader); return { - types, + ...types, showNewVisModal, - Vis: VisImpl, + /** + * creates new instance of Vis + * @param {IIndexPattern} indexPattern - index pattern to use + * @param {VisState} visState - visualization configuration + */ + createVis: (indexPattern: IIndexPattern, visState?: VisState) => + new VisImpl(indexPattern, visState), savedVisualizationsLoader, }; } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts index 2458ed5008ddd..e381a01edef8b 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts @@ -29,7 +29,8 @@ import { SavedObject, SavedObjectKibanaServices, } from '../../../../../../../plugins/saved_objects/public'; -import { updateOldState } from '../../../index'; +// @ts-ignore +import { updateOldState } from '../legacy/vis_update_state'; import { extractReferences, injectReferences } from './saved_visualization_references'; import { IIndexPattern } from '../../../../../../../plugins/data/public'; import { VisSavedObject } from '../types'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/types_service.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/types_service.ts index 0cae83afb7861..6bcaa9a3e1dac 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/types_service.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/types_service.ts @@ -67,15 +67,32 @@ export class TypesService { this.types[visDefinition.name] = visDefinition; }; return { + /** + * registers a visualization type + * @param {VisType} config - visualization type definition + */ createBaseVisualization: (config: any) => { const vis = new BaseVisType(config); registerVisualization(() => vis); }, + /** + * registers a visualization which uses react for rendering + * @param {VisType} config - visualization type definition + */ createReactVisualization: (config: any) => { const vis = new ReactVisType(config); registerVisualization(() => vis); }, + /** + * registers a visualization alias + * alias is a visualization type without implementation, it just redirects somewhere in kibana + * @param {VisTypeAlias} config - visualization alias definition + */ registerAlias: visTypeAliasRegistry.add, + /** + * allows to hide specific visualization types from create visualization dialog + * @param {string[]} typeNames - list of type ids to hide + */ hideTypes: (typeNames: string[]) => { typeNames.forEach((name: string) => { if (this.types[name]) { @@ -90,12 +107,22 @@ export class TypesService { public start() { return { + /** + * returns specific visualization or undefined if not found + * @param {string} visualization - id of visualization to return + */ get: (visualization: string) => { return this.types[visualization]; }, + /** + * returns all registered visualization types + */ all: () => { return [...Object.values(this.types)]; }, + /** + * returns all registered aliases + */ getAliases: visTypeAliasRegistry.get, }; } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx index a79c6ad98edf6..6b37845f03db1 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx @@ -29,6 +29,11 @@ export interface ShowNewVisModalParams { onClose?: () => void; } +/** + * shows modal dialog that allows you to create new visualization + * @param {string[]} editorParams + * @param {function} onClose - function that will be called when dialog is closed + */ export function showNewVisModal({ editorParams = [], onClose }: ShowNewVisModalParams = {}) { const container = document.createElement('div'); let isClosed = false; diff --git a/src/legacy/ui/public/field_editor/field_editor.js b/src/legacy/ui/public/field_editor/field_editor.js index ee88ad95eeff0..43461c4c689be 100644 --- a/src/legacy/ui/public/field_editor/field_editor.js +++ b/src/legacy/ui/public/field_editor/field_editor.js @@ -66,7 +66,7 @@ import { ScriptingHelpFlyout } from './components/scripting_help'; import { FieldFormatEditor } from './components/field_format_editor'; import { FIELD_TYPES_BY_LANG, DEFAULT_FIELD_TYPES } from './constants'; -import { copyField, getDefaultFormat, executeScript, isScriptValid } from './lib'; +import { copyField, executeScript, isScriptValid } from './lib'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -76,6 +76,25 @@ import 'brace/mode/groovy'; const getFieldFormats = () => npStart.plugins.data.fieldFormats; +const getFieldTypeFormatsList = (field, defaultFieldFormat) => { + const fieldFormats = getFieldFormats(); + const formatsByType = fieldFormats.getByFieldType(field.type).map(({ id, title }) => ({ + id, + title, + })); + + return [ + { + id: '', + defaultFieldFormat, + title: i18n.translate('common.ui.fieldEditor.defaultFormatDropDown', { + defaultMessage: '- Default -', + }), + }, + ...formatsByType, + ]; +}; + export class FieldEditor extends PureComponent { static propTypes = { indexPattern: PropTypes.object.isRequired, @@ -137,11 +156,7 @@ export class FieldEditor extends PureComponent { field.type = fieldTypes.includes(field.type) ? field.type : fieldTypes[0]; const fieldFormats = getFieldFormats(); - - const fieldTypeFormats = [ - getDefaultFormat(fieldFormats.getDefaultType(field.type, field.esTypes)), - ...fieldFormats.getByFieldType(field.type), - ]; + const DefaultFieldFormat = fieldFormats.getDefaultType(field.type, field.esTypes); this.setState({ isReady: true, @@ -150,14 +165,14 @@ export class FieldEditor extends PureComponent { errors: [], scriptingLangs, fieldTypes, - fieldTypeFormats, + fieldTypeFormats: getFieldTypeFormatsList(field, DefaultFieldFormat), fieldFormatId: get(indexPattern, ['fieldFormatMap', field.name, 'type', 'id']), fieldFormatParams: field.format.params(), }); } onFieldChange = (fieldName, value) => { - const field = this.state.field; + const { field } = this.state; field[fieldName] = value; this.forceUpdate(); }; @@ -169,18 +184,11 @@ export class FieldEditor extends PureComponent { const DefaultFieldFormat = fieldFormats.getDefaultType(type); field.type = type; - - const fieldTypeFormats = [ - getDefaultFormat(DefaultFieldFormat), - ...getFieldFormats().getByFieldType(field.type), - ]; - - const FieldFormat = fieldTypeFormats[0]; - field.format = new FieldFormat(null, getConfig); + field.format = new DefaultFieldFormat(null, getConfig); this.setState({ - fieldTypeFormats, - fieldFormatId: FieldFormat.id, + fieldTypeFormats: getFieldTypeFormatsList(field, DefaultFieldFormat), + fieldFormatId: DefaultFieldFormat.id, fieldFormatParams: field.format.params(), }); }; @@ -197,12 +205,13 @@ export class FieldEditor extends PureComponent { }; onFormatChange = (formatId, params) => { - const { getConfig } = this.props.helpers; + const fieldFormats = getFieldFormats(); const { field, fieldTypeFormats } = this.state; - const FieldFormat = - fieldTypeFormats.find(format => format.id === formatId) || fieldTypeFormats[0]; + const FieldFormat = fieldFormats.getType( + formatId || fieldTypeFormats[0]?.defaultFieldFormat.id + ); - field.format = new FieldFormat(params, getConfig); + field.format = new FieldFormat(params, this.props.helpers.getConfig); this.setState({ fieldFormatId: FieldFormat.id, @@ -416,7 +425,8 @@ export class FieldEditor extends PureComponent { renderFormat() { const { field, fieldTypeFormats, fieldFormatId, fieldFormatParams } = this.state; const { fieldFormatEditors } = this.props.helpers; - const defaultFormat = fieldTypeFormats[0] && fieldTypeFormats[0].resolvedTitle; + const defaultFormat = fieldTypeFormats[0]?.defaultFieldFormat.title; + const label = defaultFormat ? ( { - return '0,0.[000]'; -}; - -describe('getDefaultFormat', () => { - it('should create default format', () => { - const DefaultFormat = getDefaultFormat(fieldFormats.NumberFormat); - const defaultFormatObject = new DefaultFormat(null, getConfig); - const formatObject = new fieldFormats.NumberFormat(null, getConfig); - - expect(DefaultFormat.id).toEqual(''); - expect(DefaultFormat.resolvedTitle).toEqual(fieldFormats.NumberFormat.title); - expect(DefaultFormat.title).toEqual('- Default -'); - expect(JSON.stringify(defaultFormatObject.params())).toEqual( - JSON.stringify(formatObject.params()) - ); - }); -}); diff --git a/src/legacy/ui/public/field_editor/lib/get_default_format.js b/src/legacy/ui/public/field_editor/lib/get_default_format.js deleted file mode 100644 index acb7ab9c6afa5..0000000000000 --- a/src/legacy/ui/public/field_editor/lib/get_default_format.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; - -export const getDefaultFormat = Format => { - class DefaultFormat extends Format { - static id = ''; - static resolvedTitle = Format.title; - static title = i18n.translate('common.ui.fieldEditor.defaultFormatDropDown', { - defaultMessage: '- Default -', - }); - } - - return DefaultFormat; -}; diff --git a/src/legacy/ui/public/field_editor/lib/index.js b/src/legacy/ui/public/field_editor/lib/index.js index 5e12d51763a18..c74bb0cc2ef8a 100644 --- a/src/legacy/ui/public/field_editor/lib/index.js +++ b/src/legacy/ui/public/field_editor/lib/index.js @@ -18,5 +18,4 @@ */ export { copyField } from './copy_field'; -export { getDefaultFormat } from './get_default_format'; export { executeScript, isScriptValid } from './validate_script'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index a5f4ce2ce3c58..86cc0cca85e0b 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -283,8 +283,39 @@ export { * Search: */ -export { IRequestTypesMap, IResponseTypesMap } from './search'; -export * from './search'; +export { + ES_SEARCH_STRATEGY, + SYNC_SEARCH_STRATEGY, + defaultSearchStrategy, + esSearchStrategyProvider, + getEsPreference, + addSearchStrategy, + hasSearchStategyForIndexPattern, + getSearchErrorType, + ISearchContext, + TSearchStrategyProvider, + ISearchStrategy, + ISearch, + ISearchOptions, + IRequestTypesMap, + IResponseTypesMap, + ISearchGeneric, + IEsSearchResponse, + IEsSearchRequest, + ISyncSearchRequest, + IKibanaSearchResponse, + IKibanaSearchRequest, + SearchRequest, + SearchResponse, + SearchError, + SearchStrategyProvider, + ISearchSource, + SearchSource, + SearchSourceFields, + EsQuerySortValue, + SortDirection, + FetchOptions, +} from './search'; /* * UI components diff --git a/src/plugins/data/public/query/state_sync/sync_state_with_url.ts b/src/plugins/data/public/query/state_sync/sync_state_with_url.ts index cd7058b9f8f1c..77e5b0ab02dc1 100644 --- a/src/plugins/data/public/query/state_sync/sync_state_with_url.ts +++ b/src/plugins/data/public/query/state_sync/sync_state_with_url.ts @@ -85,7 +85,10 @@ export const syncQueryStateWithUrl = ( stateContainer: { ...globalQueryStateContainer, set: state => { - globalQueryStateContainer.set(state || defaultState); + if (state) { + // syncState utils requires to handle incoming "null" value + globalQueryStateContainer.set(state); + } }, }, storageKey: GLOBAL_STATE_STORAGE_KEY, diff --git a/src/plugins/data/public/search/fetch/types.ts b/src/plugins/data/public/search/fetch/types.ts index 62eb965703c3a..e8de0576b8a72 100644 --- a/src/plugins/data/public/search/fetch/types.ts +++ b/src/plugins/data/public/search/fetch/types.ts @@ -17,8 +17,8 @@ * under the License. */ -import { ISearchStart } from 'src/plugins/data/public'; import { IUiSettingsClient } from '../../../../../core/public'; +import { ISearchStart } from '../types'; export interface FetchOptions { abortSignal?: AbortSignal; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/calculate_object_hash.js b/src/plugins/kibana_utils/common/calculate_object_hash.ts similarity index 80% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/calculate_object_hash.js rename to src/plugins/kibana_utils/common/calculate_object_hash.ts index 0b6f3dc4e0826..26062636d624c 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/calculate_object_hash.js +++ b/src/plugins/kibana_utils/common/calculate_object_hash.ts @@ -19,14 +19,14 @@ // adopted form https://github.com/bevacqua/hash-sum -function pad(hash, len) { +function pad(hash: string, len: number): string { while (hash.length < len) { hash = '0' + hash; } return hash; } -function fold(hash, text) { +function fold(hash: number, text: string): number { let i; let chr; let len; @@ -35,22 +35,25 @@ function fold(hash, text) { } for (i = 0, len = text.length; i < len; i++) { chr = text.charCodeAt(i); + // eslint-disable-next-line no-bitwise hash = (hash << 5) - hash + chr; + // eslint-disable-next-line no-bitwise hash |= 0; } return hash < 0 ? hash * -2 : hash; } -function foldObject(hash, o, seen) { +function foldObject(hash: number, o: any, seen: any[]) { + function foldKey(h: number, key: string): number { + return foldValue(h, o[key], key, seen); + } + return Object.keys(o) .sort() .reduce(foldKey, hash); - function foldKey(hash, key) { - return foldValue(hash, o[key], key, seen); - } } -function foldValue(input, value, key, seen) { +function foldValue(input: number, value: any, key: string, seen: any[]) { const hash = fold(fold(fold(input, key), toString(value)), typeof value); if (value === null) { return fold(hash, 'null'); @@ -72,11 +75,11 @@ function foldValue(input, value, key, seen) { return fold(hash, value.toString()); } -function toString(o) { +function toString(o: object): string { return Object.prototype.toString.call(o); } -function sum(o) { +function sum(o: object): string { return pad(foldValue(0, o, '', []).toString(16), 8); } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/misc/default_feedback_message.test.ts b/src/plugins/kibana_utils/common/default_feedback_message.test.ts similarity index 100% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/misc/default_feedback_message.test.ts rename to src/plugins/kibana_utils/common/default_feedback_message.test.ts diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/misc/default_feedback_message.ts b/src/plugins/kibana_utils/common/default_feedback_message.ts similarity index 91% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/misc/default_feedback_message.ts rename to src/plugins/kibana_utils/common/default_feedback_message.ts index 2871437614231..f61f36bc8810c 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/misc/default_feedback_message.ts +++ b/src/plugins/kibana_utils/common/default_feedback_message.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; -export const defaultFeedbackMessage = i18n.translate('visualizations.defaultFeedbackMessage', { +export const defaultFeedbackMessage = i18n.translate('kibana_utils.defaultFeedbackMessage', { defaultMessage: 'Have feedback? Please create an issue in {link}.', values: { link: diff --git a/src/plugins/kibana_utils/common/index.ts b/src/plugins/kibana_utils/common/index.ts index 50120edc0c056..87b625ef9a64f 100644 --- a/src/plugins/kibana_utils/common/index.ts +++ b/src/plugins/kibana_utils/common/index.ts @@ -26,3 +26,5 @@ export { createGetterSetter, Get, Set } from './create_getter_setter'; export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_with_initial_value'; export { url } from './url'; export { now } from './now'; +export { calculateObjectHash } from './calculate_object_hash'; +export { defaultFeedbackMessage } from './default_feedback_message'; diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis/self_changing_vis.js b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis/self_changing_vis.js index 2976a6cd98e30..643d15c982792 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis/self_changing_vis.js +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis/self_changing_vis.js @@ -22,7 +22,7 @@ import { SelfChangingComponent } from './self_changing_components'; import { setup as visualizations } from '../../../../../../src/legacy/core_plugins/visualizations/public/np_ready/public/legacy'; -visualizations.types.createReactVisualization({ +visualizations.createReactVisualization({ name: 'self_changing_vis', title: 'Self Changing Vis', icon: 'controlsHorizontal', diff --git a/x-pack/legacy/plugins/lens/public/plugin.tsx b/x-pack/legacy/plugins/lens/public/plugin.tsx index 7f96268fc2e8c..7afe6d7abedc0 100644 --- a/x-pack/legacy/plugins/lens/public/plugin.tsx +++ b/x-pack/legacy/plugins/lens/public/plugin.tsx @@ -103,7 +103,7 @@ export class LensPlugin { this.datatableVisualization.setup(core, dependencies); this.metricVisualization.setup(core, dependencies); - visualizations.types.registerAlias(getLensAliasConfig()); + visualizations.registerAlias(getLensAliasConfig()); kibanaLegacy.registerLegacyApp({ id: 'lens', diff --git a/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js b/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js index b0e62d37fbf1c..4d87b6a055802 100644 --- a/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js +++ b/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js @@ -23,7 +23,7 @@ The Maps app offers more functionality and is easier to use.`, } ); -visualizationsSetup.types.registerAlias({ +visualizationsSetup.registerAlias({ aliasUrl: MAP_BASE_URL, name: APP_ID, title: i18n.translate('xpack.maps.visTypeAlias.title', { @@ -37,5 +37,5 @@ visualizationsSetup.types.registerAlias({ }); if (!showMapVisualizationTypes) { - visualizationsSetup.types.hideTypes(['region_map', 'tile_map']); + visualizationsSetup.hideTypes(['region_map', 'tile_map']); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 568108aff7503..5635bb19b7e83 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2849,7 +2849,6 @@ "timelion.vis.intervalLabel": "間隔", "uiActions.actionPanel.title": "オプション", "uiActions.errors.incompatibleAction": "操作に互換性がありません", - "visualizations.defaultFeedbackMessage": "フィードバックがありますか?{link} で問題を報告してください。", "visualizations.newVisWizard.betaDescription": "このビジュアライゼーションはベータ段階で、変更される可能性があります。デザインとコードはオフィシャル GA 機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャル GA 機能の SLA が適用されません", "visualizations.newVisWizard.betaTitle": "ベータ", "visualizations.newVisWizard.chooseSourceTitle": "ソースの選択", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a91f55960e34f..0523021046167 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2850,7 +2850,6 @@ "timelion.vis.intervalLabel": "时间间隔", "uiActions.actionPanel.title": "选项", "uiActions.errors.incompatibleAction": "操作不兼容", - "visualizations.defaultFeedbackMessage": "想反馈?请在“{link}中创建问题。", "visualizations.newVisWizard.betaDescription": "此可视化为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束", "visualizations.newVisWizard.betaTitle": "公测版", "visualizations.newVisWizard.chooseSourceTitle": "选择源",