onChange({ overwrite: id === overwriteEnabled.id })}
+ disabled={createNewCopies}
+ data-test-subj={'savedObjectsManagement-importModeControl-overwriteRadioGroup'}
+ />
diff --git a/src/plugins/share/public/index.ts b/src/plugins/share/public/index.ts
index 1f999b59ddb61..74e849948d418 100644
--- a/src/plugins/share/public/index.ts
+++ b/src/plugins/share/public/index.ts
@@ -31,6 +31,7 @@ export {
UrlGeneratorsService,
} from './url_generators';
+export { RedirectOptions } from './url_service';
export { useLocatorUrl } from '../common/url_service/locators/use_locator_url';
import { SharePlugin } from './plugin';
diff --git a/src/plugins/share/public/url_service/redirect/redirect_manager.ts b/src/plugins/share/public/url_service/redirect/redirect_manager.ts
index cc45e0d3126af..a5d895c7cbcf0 100644
--- a/src/plugins/share/public/url_service/redirect/redirect_manager.ts
+++ b/src/plugins/share/public/url_service/redirect/redirect_manager.ts
@@ -15,7 +15,15 @@ import type { UrlService } from '../../../common/url_service';
import { render } from './render';
import { parseSearchParams } from './util/parse_search_params';
-export interface RedirectOptions {
+/**
+ * @public
+ * Serializable locator parameters that can be used by the redirect service to navigate to a location
+ * in Kibana.
+ *
+ * When passed to the public {@link SharePluginSetup['navigate']} function, locator params will also be
+ * migrated.
+ */
+export interface RedirectOptions {
/** Locator ID. */
id: string;
@@ -23,7 +31,7 @@ export interface RedirectOptions {
version: string;
/** Locator params. */
- params: unknown & SerializableRecord;
+ params: P;
}
export interface RedirectManagerDependencies {
diff --git a/src/plugins/url_forwarding/kibana.json b/src/plugins/url_forwarding/kibana.json
index a8b0571230b72..3e48cf73de5ef 100644
--- a/src/plugins/url_forwarding/kibana.json
+++ b/src/plugins/url_forwarding/kibana.json
@@ -6,6 +6,5 @@
"owner": {
"name": "Vis Editors",
"githubTeam": "kibana-vis-editors"
- },
- "requiredPlugins": ["kibanaLegacy"]
+ }
}
diff --git a/src/plugins/url_forwarding/public/forward_app/forward_app.test.ts b/src/plugins/url_forwarding/public/forward_app/forward_app.test.ts
new file mode 100644
index 0000000000000..c45bde0d67891
--- /dev/null
+++ b/src/plugins/url_forwarding/public/forward_app/forward_app.test.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+import type { Location } from 'history';
+import type { AppMountParameters, CoreSetup, ScopedHistory } from 'kibana/public';
+import { coreMock } from '../../../../core/public/mocks';
+import type { UrlForwardingStart } from '../plugin';
+import { createLegacyUrlForwardApp } from './forward_app';
+
+function createAppMountParams(hash: string): AppMountParameters {
+ return {
+ history: {
+ location: {
+ hash,
+ } as Location,
+ } as ScopedHistory,
+ } as AppMountParameters;
+}
+
+describe('forward_app', () => {
+ let coreSetup: CoreSetup<{}, UrlForwardingStart>;
+ let coreStart: ReturnType;
+
+ beforeEach(() => {
+ coreSetup = coreMock.createSetup({ basePath: '/base/path' });
+ coreStart = coreMock.createStart({ basePath: '/base/path' });
+ coreSetup.getStartServices = () => Promise.resolve([coreStart, {}, {} as any]);
+ });
+
+ it('should forward to defaultRoute if hash is not a known redirect', async () => {
+ coreStart.uiSettings.get.mockImplementation((key) => {
+ if (key === 'defaultRoute') return '/app/defaultApp';
+ throw new Error('Mock implementation missing');
+ });
+
+ const app = createLegacyUrlForwardApp(coreSetup, [
+ { legacyAppId: 'discover', newAppId: 'discover', rewritePath: (p) => p },
+ ]);
+ await app.mount(createAppMountParams('#/foobar'));
+ expect(coreStart.application.navigateToUrl).toHaveBeenCalledWith('/base/path/app/defaultApp');
+ });
+
+ it('should not forward to defaultRoute if hash path is a known redirect', async () => {
+ const app = createLegacyUrlForwardApp(coreSetup, [
+ { legacyAppId: 'discover', newAppId: 'discover', rewritePath: (p) => p },
+ ]);
+ await app.mount(createAppMountParams('#/discover'));
+ expect(coreStart.application.navigateToUrl).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/plugins/url_forwarding/public/forward_app/forward_app.ts b/src/plugins/url_forwarding/public/forward_app/forward_app.ts
index 96c4fab5f3331..3a66e207f8c26 100644
--- a/src/plugins/url_forwarding/public/forward_app/forward_app.ts
+++ b/src/plugins/url_forwarding/public/forward_app/forward_app.ts
@@ -23,23 +23,18 @@ export const createLegacyUrlForwardApp = (
async mount(params: AppMountParameters) {
const hash = params.history.location.hash.substr(1);
- if (!hash) {
- const [, , kibanaLegacyStart] = await core.getStartServices();
- kibanaLegacyStart.navigateToDefaultApp();
- }
-
const [
{
application,
+ uiSettings,
http: { basePath },
},
] = await core.getStartServices();
- const result = await navigateToLegacyKibanaUrl(hash, forwards, basePath, application);
-
- if (!result.navigated) {
- const [, , kibanaLegacyStart] = await core.getStartServices();
- kibanaLegacyStart.navigateToDefaultApp();
+ const { navigated } = navigateToLegacyKibanaUrl(hash, forwards, basePath, application);
+ if (!navigated) {
+ const defaultRoute = uiSettings.get('defaultRoute');
+ application.navigateToUrl(basePath.prepend(defaultRoute));
}
return () => {};
diff --git a/src/plugins/url_forwarding/public/mocks.ts b/src/plugins/url_forwarding/public/mocks.ts
index 67b521b9d697d..582bb004b655e 100644
--- a/src/plugins/url_forwarding/public/mocks.ts
+++ b/src/plugins/url_forwarding/public/mocks.ts
@@ -17,7 +17,6 @@ const createSetupContract = (): Setup => ({
const createStartContract = (): Start => ({
getForwards: jest.fn(),
- navigateToDefaultApp: jest.fn(),
navigateToLegacyKibanaUrl: jest.fn(),
});
diff --git a/src/plugins/url_forwarding/public/navigate_to_default_app.ts b/src/plugins/url_forwarding/public/navigate_to_default_app.ts
deleted file mode 100644
index 0c934ac9c6844..0000000000000
--- a/src/plugins/url_forwarding/public/navigate_to_default_app.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import { ApplicationStart, IBasePath } from 'kibana/public';
-import { ForwardDefinition } from './plugin';
-
-export function navigateToDefaultApp(
- defaultAppId: string,
- forwards: ForwardDefinition[],
- application: ApplicationStart,
- basePath: IBasePath,
- currentAppId: string | undefined,
- overwriteHash: boolean
-) {
- // navigate to the respective path in the legacy kibana plugin by default (for unmigrated plugins)
- let targetAppId = 'kibana';
- let targetAppPath = `#/${defaultAppId}`;
-
- // try to find an existing redirect for the target path if possible
- // this avoids having to load the legacy app just to get redirected to a core application again afterwards
- const relevantForward = forwards.find((forward) => defaultAppId.startsWith(forward.legacyAppId));
- if (relevantForward) {
- targetAppPath = relevantForward.rewritePath(`/${defaultAppId}`);
- targetAppId = relevantForward.newAppId;
- }
-
- // when the correct app is already loaded, just set the hash to the right value
- // otherwise use navigateToApp (or setting href in case of kibana app)
- if (currentAppId !== targetAppId) {
- application.navigateToApp(targetAppId, { path: targetAppPath, replace: true });
- } else if (overwriteHash) {
- window.location.hash = targetAppPath;
- }
-}
diff --git a/src/plugins/url_forwarding/public/plugin.ts b/src/plugins/url_forwarding/public/plugin.ts
index 1151e853f28ba..ee56ba73eb24e 100644
--- a/src/plugins/url_forwarding/public/plugin.ts
+++ b/src/plugins/url_forwarding/public/plugin.ts
@@ -7,9 +7,6 @@
*/
import { CoreStart, CoreSetup } from 'kibana/public';
-import { KibanaLegacyStart } from 'src/plugins/kibana_legacy/public';
-import { Subscription } from 'rxjs';
-import { navigateToDefaultApp } from './navigate_to_default_app';
import { createLegacyUrlForwardApp } from './forward_app';
import { navigateToLegacyKibanaUrl } from './forward_app/navigate_to_legacy_kibana_url';
@@ -21,8 +18,6 @@ export interface ForwardDefinition {
export class UrlForwardingPlugin {
private forwardDefinitions: ForwardDefinition[] = [];
- private currentAppId: string | undefined;
- private currentAppIdSubscription: Subscription | undefined;
public setup(core: CoreSetup<{}, UrlForwardingStart>) {
core.application.register(createLegacyUrlForwardApp(core, this.forwardDefinitions));
@@ -71,30 +66,8 @@ export class UrlForwardingPlugin {
};
}
- public start(
- { application, http: { basePath }, uiSettings }: CoreStart,
- { kibanaLegacy }: { kibanaLegacy: KibanaLegacyStart }
- ) {
- this.currentAppIdSubscription = application.currentAppId$.subscribe((currentAppId) => {
- this.currentAppId = currentAppId;
- });
+ public start({ application, http: { basePath } }: CoreStart) {
return {
- /**
- * Navigates to the app defined as kibana.defaultAppId.
- * This takes redirects into account and uses the right mechanism to navigate.
- */
- navigateToDefaultApp: (
- { overwriteHash }: { overwriteHash: boolean } = { overwriteHash: true }
- ) => {
- navigateToDefaultApp(
- kibanaLegacy.config.defaultAppId,
- this.forwardDefinitions,
- application,
- basePath,
- this.currentAppId,
- overwriteHash
- );
- },
/**
* Resolves the provided hash using the registered forwards and navigates to the target app.
* If a navigation happened, `{ navigated: true }` will be returned.
@@ -111,12 +84,6 @@ export class UrlForwardingPlugin {
getForwards: () => this.forwardDefinitions,
};
}
-
- public stop() {
- if (this.currentAppIdSubscription) {
- this.currentAppIdSubscription.unsubscribe();
- }
- }
}
export type UrlForwardingSetup = ReturnType;
diff --git a/src/plugins/vis_types/metric/public/components/metric_vis_component.tsx b/src/plugins/vis_types/metric/public/components/metric_vis_component.tsx
index c3735bdc0d79a..837ec5ff60dc5 100644
--- a/src/plugins/vis_types/metric/public/components/metric_vis_component.tsx
+++ b/src/plugins/vis_types/metric/public/components/metric_vis_component.tsx
@@ -16,7 +16,7 @@ import { Datatable } from '../../../../expressions/public';
import { getHeatmapColors } from '../../../../charts/public';
import { VisParams, MetricVisMetric } from '../types';
import { getFormatService } from '../services';
-import { SchemaConfig } from '../../../../visualizations/public';
+import { ExpressionValueVisDimension } from '../../../../visualizations/public';
import { Range } from '../../../../expressions/public';
import './metric_vis.scss';
@@ -98,6 +98,16 @@ class MetricVisComponent extends Component {
return fieldFormatter.convert(value, format);
};
+ private getColumn(
+ accessor: ExpressionValueVisDimension['accessor'],
+ columns: Datatable['columns'] = []
+ ) {
+ if (typeof accessor === 'number') {
+ return columns[accessor];
+ }
+ return columns.filter(({ id }) => accessor.id === id)[0];
+ }
+
private processTableGroups(table: Datatable) {
const config = this.props.visParams.metric;
const dimensions = this.props.visParams.dimensions;
@@ -112,13 +122,12 @@ class MetricVisComponent extends Component {
let bucketFormatter: IFieldFormat;
if (dimensions.bucket) {
- bucketColumnId = table.columns[dimensions.bucket.accessor].id;
+ bucketColumnId = this.getColumn(dimensions.bucket.accessor, table.columns).id;
bucketFormatter = getFormatService().deserialize(dimensions.bucket.format);
}
- dimensions.metrics.forEach((metric: SchemaConfig) => {
- const columnIndex = metric.accessor;
- const column = table?.columns[columnIndex];
+ dimensions.metrics.forEach((metric: ExpressionValueVisDimension) => {
+ const column = this.getColumn(metric.accessor, table?.columns);
const formatter = getFormatService().deserialize(metric.format);
table.rows.forEach((row, rowIndex) => {
let title = column.name;
diff --git a/src/plugins/vis_types/metric/public/metric_vis_fn.ts b/src/plugins/vis_types/metric/public/metric_vis_fn.ts
index 9a144defed4e7..210552732bc0a 100644
--- a/src/plugins/vis_types/metric/public/metric_vis_fn.ts
+++ b/src/plugins/vis_types/metric/public/metric_vis_fn.ts
@@ -15,9 +15,10 @@ import {
Render,
Style,
} from '../../../expressions/public';
-import { visType, DimensionsVisParam, VisParams } from './types';
+import { visType, VisParams } from './types';
import { prepareLogTable, Dimension } from '../../../visualizations/public';
import { ColorSchemas, vislibColorMaps, ColorMode } from '../../../charts/public';
+import { ExpressionValueVisDimension } from '../../../visualizations/public';
export type Input = Datatable;
@@ -32,8 +33,8 @@ interface Arguments {
subText: string;
colorRange: Range[];
font: Style;
- metric: any[]; // these aren't typed yet
- bucket: any; // these aren't typed yet
+ metric: ExpressionValueVisDimension[];
+ bucket: ExpressionValueVisDimension;
}
export interface MetricVisRenderValue {
@@ -150,14 +151,6 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({
},
},
fn(input, args, handlers) {
- const dimensions: DimensionsVisParam = {
- metrics: args.metric,
- };
-
- if (args.bucket) {
- dimensions.bucket = args.bucket;
- }
-
if (args.percentageMode && (!args.colorRange || args.colorRange.length === 0)) {
throw new Error('colorRange must be provided when using percentageMode');
}
@@ -184,6 +177,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({
const logTable = prepareLogTable(input, argsTable);
handlers.inspectorAdapters.tables.logDatatable('default', logTable);
}
+
return {
type: 'render',
as: 'metric_vis',
@@ -209,7 +203,10 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({
fontSize,
},
},
- dimensions,
+ dimensions: {
+ metrics: args.metric,
+ ...(args.bucket ? { bucket: args.bucket } : {}),
+ },
},
},
};
diff --git a/src/plugins/vis_types/metric/public/types.ts b/src/plugins/vis_types/metric/public/types.ts
index 1baaa25959f31..8e86c0217bba6 100644
--- a/src/plugins/vis_types/metric/public/types.ts
+++ b/src/plugins/vis_types/metric/public/types.ts
@@ -7,14 +7,14 @@
*/
import { Range } from '../../../expressions/public';
-import { SchemaConfig } from '../../../visualizations/public';
+import { ExpressionValueVisDimension } from '../../../visualizations/public';
import { ColorMode, Labels, Style, ColorSchemas } from '../../../charts/public';
export const visType = 'metric';
export interface DimensionsVisParam {
- metrics: SchemaConfig[];
- bucket?: SchemaConfig;
+ metrics: ExpressionValueVisDimension[];
+ bucket?: ExpressionValueVisDimension;
}
export interface MetricVisParam {
diff --git a/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap
index fed6fb54288f2..9e4c3071db8d6 100644
--- a/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap
+++ b/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap
@@ -1,6 +1,108 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`tagcloud vis toExpressionAst function should match snapshot params fulfilled 1`] = `
+exports[`tagcloud vis toExpressionAst function should match snapshot params fulfilled with DatatableColumn vis_dimension.accessor at metric 1`] = `
+Object {
+ "chain": Array [
+ Object {
+ "arguments": Object {
+ "aggs": Array [],
+ "index": Array [
+ Object {
+ "chain": Array [
+ Object {
+ "arguments": Object {
+ "id": Array [
+ "123",
+ ],
+ },
+ "function": "indexPatternLoad",
+ "type": "function",
+ },
+ ],
+ "type": "expression",
+ },
+ ],
+ "metricsAtAllLevels": Array [
+ false,
+ ],
+ "partialRows": Array [
+ false,
+ ],
+ },
+ "function": "esaggs",
+ "type": "function",
+ },
+ Object {
+ "arguments": Object {
+ "bucket": Array [
+ Object {
+ "chain": Array [
+ Object {
+ "arguments": Object {
+ "accessor": Array [
+ 0,
+ ],
+ "format": Array [
+ "terms",
+ ],
+ "formatParams": Array [
+ "{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\"}",
+ ],
+ },
+ "function": "visdimension",
+ "type": "function",
+ },
+ ],
+ "type": "expression",
+ },
+ ],
+ "maxFontSize": Array [
+ 15,
+ ],
+ "metric": Array [
+ Object {
+ "chain": Array [
+ Object {
+ "arguments": Object {
+ "accessor": Array [
+ 1,
+ ],
+ "format": Array [
+ "number",
+ ],
+ },
+ "function": "visdimension",
+ "type": "function",
+ },
+ ],
+ "type": "expression",
+ },
+ ],
+ "minFontSize": Array [
+ 5,
+ ],
+ "orientation": Array [
+ "single",
+ ],
+ "palette": Array [
+ "default",
+ ],
+ "scale": Array [
+ "linear",
+ ],
+ "showLabel": Array [
+ true,
+ ],
+ },
+ "function": "tagcloud",
+ "type": "function",
+ },
+ ],
+ "type": "expression",
+}
+`;
+
+exports[`tagcloud vis toExpressionAst function should match snapshot params fulfilled with number vis_dimension.accessor at metric 1`] = `
Object {
"chain": Array [
Object {
diff --git a/src/plugins/vis_types/tagcloud/public/to_ast.test.ts b/src/plugins/vis_types/tagcloud/public/to_ast.test.ts
index c70448ab113cb..6de1d4fb3e75d 100644
--- a/src/plugins/vis_types/tagcloud/public/to_ast.test.ts
+++ b/src/plugins/vis_types/tagcloud/public/to_ast.test.ts
@@ -6,11 +6,11 @@
* Side Public License, v 1.
*/
-import { Vis } from 'src/plugins/visualizations/public';
+import { Vis, VisToExpressionAstParams } from '../../../visualizations/public';
import { toExpressionAst } from './to_ast';
import { TagCloudVisParams } from './types';
-const mockSchemas = {
+const mockedSchemas = {
metric: [{ accessor: 1, format: { id: 'number' }, params: {}, label: 'Count', aggType: 'count' }],
segment: [
{
@@ -31,14 +31,14 @@ const mockSchemas = {
};
jest.mock('../../../visualizations/public', () => ({
- getVisSchemas: () => mockSchemas,
+ getVisSchemas: () => mockedSchemas,
}));
describe('tagcloud vis toExpressionAst function', () => {
let vis: Vis;
beforeEach(() => {
- vis = {
+ vis = ({
isHierarchical: () => false,
type: {},
params: {
@@ -51,15 +51,15 @@ describe('tagcloud vis toExpressionAst function', () => {
aggs: [],
},
},
- } as any;
+ } as unknown) as Vis;
});
it('should match snapshot without params', () => {
- const actual = toExpressionAst(vis, {} as any);
+ const actual = toExpressionAst(vis, {} as VisToExpressionAstParams);
expect(actual).toMatchSnapshot();
});
- it('should match snapshot params fulfilled', () => {
+ it('should match snapshot params fulfilled with number vis_dimension.accessor at metric', () => {
vis.params = {
scale: 'linear',
orientation: 'single',
@@ -70,9 +70,48 @@ describe('tagcloud vis toExpressionAst function', () => {
type: 'palette',
name: 'default',
},
- metric: { accessor: 0, format: { id: 'number' } },
+ metric: {
+ type: 'vis_dimension',
+ accessor: 0,
+ format: {
+ id: 'number',
+ params: {
+ id: 'number',
+ },
+ },
+ },
+ };
+ const actual = toExpressionAst(vis, {} as VisToExpressionAstParams);
+ expect(actual).toMatchSnapshot();
+ });
+
+ it('should match snapshot params fulfilled with DatatableColumn vis_dimension.accessor at metric', () => {
+ vis.params = {
+ scale: 'linear',
+ orientation: 'single',
+ minFontSize: 5,
+ maxFontSize: 15,
+ showLabel: true,
+ palette: {
+ type: 'palette',
+ name: 'default',
+ },
+ metric: {
+ type: 'vis_dimension',
+ accessor: {
+ id: 'count',
+ name: 'count',
+ meta: { type: 'number' },
+ },
+ format: {
+ id: 'number',
+ params: {
+ id: 'number',
+ },
+ },
+ },
};
- const actual = toExpressionAst(vis, {} as any);
+ const actual = toExpressionAst(vis, {} as VisToExpressionAstParams);
expect(actual).toMatchSnapshot();
});
});
diff --git a/src/plugins/vis_types/tagcloud/public/types.ts b/src/plugins/vis_types/tagcloud/public/types.ts
index 28a7c6506eb31..996555ae99f83 100644
--- a/src/plugins/vis_types/tagcloud/public/types.ts
+++ b/src/plugins/vis_types/tagcloud/public/types.ts
@@ -6,15 +6,7 @@
* Side Public License, v 1.
*/
import type { ChartsPluginSetup, PaletteOutput } from '../../../charts/public';
-import type { SerializedFieldFormat } from '../../../expressions/public';
-
-interface Dimension {
- accessor: number;
- format: {
- id?: string;
- params?: SerializedFieldFormat