+
+
+
+
+
+
+
+
+
+
+
+
+
+ Manage cloud deployment
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{},
closeNav: () => {},
navigateToApp: () => Promise.resolve(),
+ customNavLink$: new BehaviorSubject(undefined),
};
}
@@ -120,12 +121,14 @@ describe('CollapsibleNav', () => {
mockRecentNavLink({ label: 'recent 1' }),
mockRecentNavLink({ label: 'recent 2' }),
];
+ const customNavLink = mockLink({ title: 'Custom link' });
const component = mount(
);
expect(component).toMatchSnapshot();
diff --git a/src/core/public/chrome/ui/header/collapsible_nav.tsx b/src/core/public/chrome/ui/header/collapsible_nav.tsx
index 9494e22920de..07541b1adff1 100644
--- a/src/core/public/chrome/ui/header/collapsible_nav.tsx
+++ b/src/core/public/chrome/ui/header/collapsible_nav.tsx
@@ -30,7 +30,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { groupBy, sortBy } from 'lodash';
-import React, { useRef } from 'react';
+import React, { Fragment, useRef } from 'react';
import { useObservable } from 'react-use';
import * as Rx from 'rxjs';
import { ChromeNavLink, ChromeRecentlyAccessedHistoryItem } from '../..';
@@ -88,6 +88,7 @@ interface Props {
onIsLockedUpdate: OnIsLockedUpdate;
closeNav: () => void;
navigateToApp: InternalApplicationStart['navigateToApp'];
+ customNavLink$: Rx.Observable;
}
export function CollapsibleNav({
@@ -105,6 +106,7 @@ export function CollapsibleNav({
}: Props) {
const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden);
const recentlyAccessed = useObservable(observables.recentlyAccessed$, []);
+ const customNavLink = useObservable(observables.customNavLink$, undefined);
const appId = useObservable(observables.appId$, '');
const lockRef = useRef(null);
const groupedNavLinks = groupBy(navLinks, (link) => link?.category?.id);
@@ -134,6 +136,38 @@ export function CollapsibleNav({
isDocked={isLocked}
onClose={closeNav}
>
+ {customNavLink && (
+
+
+
+
+
+
+
+
+
+ )}
+
{/* Pinned items */}
{
const navLinks$ = new BehaviorSubject([
{ id: 'kibana', title: 'kibana', baseUrl: '', legacy: false },
]);
+ const customNavLink$ = new BehaviorSubject({
+ id: 'cloud-deployment-link',
+ title: 'Manage cloud deployment',
+ baseUrl: '',
+ legacy: false,
+ });
const recentlyAccessed$ = new BehaviorSubject([
{ link: '', label: 'dashboard', id: 'dashboard' },
]);
@@ -87,6 +94,7 @@ describe('Header', () => {
recentlyAccessed$={recentlyAccessed$}
isLocked$={isLocked$}
navType$={navType$}
+ customNavLink$={customNavLink$}
/>
);
expect(component).toMatchSnapshot();
diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx
index d24b342e0386..3da3caaaa4a4 100644
--- a/src/core/public/chrome/ui/header/header.tsx
+++ b/src/core/public/chrome/ui/header/header.tsx
@@ -58,6 +58,7 @@ export interface HeaderProps {
appTitle$: Observable;
badge$: Observable;
breadcrumbs$: Observable;
+ customNavLink$: Observable;
homeHref: string;
isVisible$: Observable;
kibanaDocLink: string;
@@ -203,6 +204,7 @@ export function Header({
toggleCollapsibleNavRef.current.focus();
}
}}
+ customNavLink$={observables.customNavLink$}
/>
) : (
// TODO #64541
diff --git a/src/core/public/chrome/ui/header/nav_link.tsx b/src/core/public/chrome/ui/header/nav_link.tsx
index 969b6728e026..6b5cecd13837 100644
--- a/src/core/public/chrome/ui/header/nav_link.tsx
+++ b/src/core/public/chrome/ui/header/nav_link.tsx
@@ -35,11 +35,12 @@ function LinkIcon({ url }: { url: string }) {
interface Props {
link: ChromeNavLink;
legacyMode: boolean;
- appId: string | undefined;
+ appId?: string;
basePath?: HttpStart['basePath'];
dataTestSubj: string;
onClick?: Function;
navigateToApp: CoreStart['application']['navigateToApp'];
+ externalLink?: boolean;
}
// TODO #64541
@@ -54,6 +55,7 @@ export function createEuiListItem({
onClick = () => {},
navigateToApp,
dataTestSubj,
+ externalLink = false,
}: Props) {
const { legacy, active, id, title, disabled, euiIconType, icon, tooltip } = link;
let { href } = link;
@@ -69,6 +71,7 @@ export function createEuiListItem({
onClick(event: React.MouseEvent) {
onClick();
if (
+ !externalLink && // ignore external links
!legacyMode && // ignore when in legacy mode
!legacy && // ignore links to legacy apps
!event.defaultPrevented && // onClick prevented default
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index 9a79576b14d1..d10e351f4d13 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -154,6 +154,7 @@ export function __kbnBootstrap__(): void;
export interface App extends AppBase {
appRoute?: string;
chromeless?: boolean;
+ exactRoute?: boolean;
mount: AppMount | AppMountDeprecated;
}
@@ -466,6 +467,7 @@ export interface ChromeStart {
getBadge$(): Observable;
getBrand$(): Observable;
getBreadcrumbs$(): Observable;
+ getCustomNavLink$(): Observable | undefined>;
getHelpExtension$(): Observable;
getIsNavDrawerLocked$(): Observable;
getIsVisible$(): Observable;
@@ -478,6 +480,7 @@ export interface ChromeStart {
setBadge(badge?: ChromeBadge): void;
setBrand(brand: ChromeBrand): void;
setBreadcrumbs(newBreadcrumbs: ChromeBreadcrumb[]): void;
+ setCustomNavLink(newCustomNavLink?: Partial): void;
setHelpExtension(helpExtension?: ChromeHelpExtension): void;
setHelpSupportUrl(url: string): void;
setIsVisible(isVisible: boolean): void;
diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts
index 1e0b631308d9..065321e35525 100644
--- a/src/dev/typescript/projects.ts
+++ b/src/dev/typescript/projects.ts
@@ -34,6 +34,10 @@ export const PROJECTS = [
name: 'apm/cypress',
disableTypeCheck: true,
}),
+ new Project(resolve(REPO_ROOT, 'x-pack/plugins/apm/scripts/tsconfig.json'), {
+ name: 'apm/scripts',
+ disableTypeCheck: true,
+ }),
// NOTE: using glob.sync rather than glob-all or globby
// because it takes less than 10 ms, while the other modules
diff --git a/src/plugins/share/server/saved_objects/url.ts b/src/plugins/share/server/saved_objects/url.ts
index c76c21993a13..3ea64ad4719f 100644
--- a/src/plugins/share/server/saved_objects/url.ts
+++ b/src/plugins/share/server/saved_objects/url.ts
@@ -46,6 +46,7 @@ export const url: SavedObjectsType = {
fields: {
keyword: {
type: 'keyword',
+ ignore_above: 2048,
},
},
},
diff --git a/src/plugins/usage_collection/public/plugin.ts b/src/plugins/usage_collection/public/plugin.ts
index cf2f6af1507c..40f27f826992 100644
--- a/src/plugins/usage_collection/public/plugin.ts
+++ b/src/plugins/usage_collection/public/plugin.ts
@@ -52,12 +52,17 @@ export interface UsageCollectionSetup {
};
}
+export interface UsageCollectionStart {
+ reportUiStats: Reporter['reportUiStats'];
+ METRIC_TYPE: typeof METRIC_TYPE;
+}
+
export function isUnauthenticated(http: HttpSetup) {
const { anonymousPaths } = http;
return anonymousPaths.isAnonymous(window.location.pathname);
}
-export class UsageCollectionPlugin implements Plugin {
+export class UsageCollectionPlugin implements Plugin {
private readonly legacyAppId$ = new Subject();
private trackUserAgent: boolean = true;
private reporter?: Reporter;
@@ -90,7 +95,7 @@ export class UsageCollectionPlugin implements Plugin {
public start({ http, application }: CoreStart) {
if (!this.reporter) {
- return;
+ throw new Error('Usage collection reporter not set up correctly');
}
if (this.config.uiMetric.enabled && !isUnauthenticated(http)) {
@@ -100,7 +105,13 @@ export class UsageCollectionPlugin implements Plugin {
if (this.trackUserAgent) {
this.reporter.reportUserAgent('kibana');
}
+
reportApplicationUsage(merge(application.currentAppId$, this.legacyAppId$), this.reporter);
+
+ return {
+ reportUiStats: this.reporter.reportUiStats,
+ METRIC_TYPE,
+ };
}
public stop() {}
diff --git a/src/plugins/vis_type_timeseries/common/types.ts b/src/plugins/vis_type_timeseries/common/types.ts
new file mode 100644
index 000000000000..452006924452
--- /dev/null
+++ b/src/plugins/vis_type_timeseries/common/types.ts
@@ -0,0 +1,25 @@
+/*
+ * 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 { TypeOf } from '@kbn/config-schema';
+import { metricsItems, panel, seriesItems } from './vis_schema';
+
+export type SeriesItemsSchema = TypeOf;
+export type MetricsItemsSchema = TypeOf;
+export type PanelSchema = TypeOf;
diff --git a/src/plugins/vis_type_timeseries/common/ui_restrictions.js b/src/plugins/vis_type_timeseries/common/ui_restrictions.ts
similarity index 73%
rename from src/plugins/vis_type_timeseries/common/ui_restrictions.js
rename to src/plugins/vis_type_timeseries/common/ui_restrictions.ts
index 96726d51e4a7..4508735f39ff 100644
--- a/src/plugins/vis_type_timeseries/common/ui_restrictions.js
+++ b/src/plugins/vis_type_timeseries/common/ui_restrictions.ts
@@ -22,21 +22,30 @@
* @constant
* @public
*/
-export const RESTRICTIONS_KEYS = {
+export enum RESTRICTIONS_KEYS {
/**
* Key for getting the white listed group by fields from the UIRestrictions object.
*/
- WHITE_LISTED_GROUP_BY_FIELDS: 'whiteListedGroupByFields',
+ WHITE_LISTED_GROUP_BY_FIELDS = 'whiteListedGroupByFields',
/**
* Key for getting the white listed metrics from the UIRestrictions object.
*/
- WHITE_LISTED_METRICS: 'whiteListedMetrics',
+ WHITE_LISTED_METRICS = 'whiteListedMetrics',
/**
* Key for getting the white listed Time Range modes from the UIRestrictions object.
*/
- WHITE_LISTED_TIMERANGE_MODES: 'whiteListedTimerangeModes',
+ WHITE_LISTED_TIMERANGE_MODES = 'whiteListedTimerangeModes',
+}
+
+export interface UIRestrictions {
+ '*': boolean;
+ [restriction: string]: boolean;
+}
+
+export type TimeseriesUIRestrictions = {
+ [key in RESTRICTIONS_KEYS]: Record;
};
/**
@@ -44,6 +53,6 @@ export const RESTRICTIONS_KEYS = {
* @constant
* @public
*/
-export const DEFAULT_UI_RESTRICTION = {
+export const DEFAULT_UI_RESTRICTION: UIRestrictions = {
'*': true,
};
diff --git a/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts b/src/plugins/vis_type_timeseries/common/vis_schema.ts
similarity index 73%
rename from src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts
rename to src/plugins/vis_type_timeseries/common/vis_schema.ts
index bf2ea8651c5a..7161c197b694 100644
--- a/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts
+++ b/src/plugins/vis_type_timeseries/common/vis_schema.ts
@@ -76,7 +76,7 @@ const gaugeColorRulesItems = schema.object({
operator: stringOptionalNullable,
value: schema.maybe(schema.nullable(schema.number())),
});
-const metricsItems = schema.object({
+export const metricsItems = schema.object({
field: stringOptionalNullable,
id: stringRequired,
metric_agg: stringOptionalNullable,
@@ -133,7 +133,7 @@ const splitFiltersItems = schema.object({
label: stringOptionalNullable,
});
-const seriesItems = schema.object({
+export const seriesItems = schema.object({
aggregate_by: stringOptionalNullable,
aggregate_function: stringOptionalNullable,
axis_position: stringRequired,
@@ -195,66 +195,66 @@ const seriesItems = schema.object({
var_name: stringOptionalNullable,
});
+export const panel = schema.object({
+ annotations: schema.maybe(schema.arrayOf(annotationsItems)),
+ axis_formatter: stringRequired,
+ axis_position: stringRequired,
+ axis_scale: stringRequired,
+ axis_min: stringOrNumberOptionalNullable,
+ axis_max: stringOrNumberOptionalNullable,
+ bar_color_rules: schema.maybe(arrayNullable),
+ background_color: stringOptionalNullable,
+ background_color_rules: schema.maybe(schema.arrayOf(backgroundColorRulesItems)),
+ default_index_pattern: stringOptionalNullable,
+ default_timefield: stringOptionalNullable,
+ drilldown_url: stringOptionalNullable,
+ drop_last_bucket: numberIntegerOptional,
+ filter: schema.nullable(
+ schema.oneOf([
+ stringOptionalNullable,
+ schema.object({
+ language: stringOptionalNullable,
+ query: stringOptionalNullable,
+ }),
+ ])
+ ),
+ gauge_color_rules: schema.maybe(schema.arrayOf(gaugeColorRulesItems)),
+ gauge_width: schema.nullable(schema.oneOf([stringOptionalNullable, numberOptional])),
+ gauge_inner_color: stringOptionalNullable,
+ gauge_inner_width: stringOrNumberOptionalNullable,
+ gauge_style: stringOptionalNullable,
+ gauge_max: stringOrNumberOptionalNullable,
+ id: stringRequired,
+ ignore_global_filters: numberOptional,
+ ignore_global_filter: numberOptional,
+ index_pattern: stringRequired,
+ interval: stringRequired,
+ isModelInvalid: schema.maybe(schema.boolean()),
+ legend_position: stringOptionalNullable,
+ markdown: stringOptionalNullable,
+ markdown_scrollbars: numberIntegerOptional,
+ markdown_openLinksInNewTab: numberIntegerOptional,
+ markdown_vertical_align: stringOptionalNullable,
+ markdown_less: stringOptionalNullable,
+ markdown_css: stringOptionalNullable,
+ pivot_id: stringOptionalNullable,
+ pivot_label: stringOptionalNullable,
+ pivot_type: stringOptionalNullable,
+ pivot_rows: stringOptionalNullable,
+ series: schema.arrayOf(seriesItems),
+ show_grid: numberIntegerRequired,
+ show_legend: numberIntegerRequired,
+ tooltip_mode: schema.maybe(
+ schema.oneOf([schema.literal('show_all'), schema.literal('show_focused')])
+ ),
+ time_field: stringOptionalNullable,
+ time_range_mode: stringOptionalNullable,
+ type: stringRequired,
+});
+
export const visPayloadSchema = schema.object({
filters: arrayNullable,
- panels: schema.arrayOf(
- schema.object({
- annotations: schema.maybe(schema.arrayOf(annotationsItems)),
- axis_formatter: stringRequired,
- axis_position: stringRequired,
- axis_scale: stringRequired,
- axis_min: stringOrNumberOptionalNullable,
- axis_max: stringOrNumberOptionalNullable,
- bar_color_rules: schema.maybe(arrayNullable),
- background_color: stringOptionalNullable,
- background_color_rules: schema.maybe(schema.arrayOf(backgroundColorRulesItems)),
- default_index_pattern: stringOptionalNullable,
- default_timefield: stringOptionalNullable,
- drilldown_url: stringOptionalNullable,
- drop_last_bucket: numberIntegerOptional,
- filter: schema.nullable(
- schema.oneOf([
- stringOptionalNullable,
- schema.object({
- language: stringOptionalNullable,
- query: stringOptionalNullable,
- }),
- ])
- ),
- gauge_color_rules: schema.maybe(schema.arrayOf(gaugeColorRulesItems)),
- gauge_width: schema.nullable(schema.oneOf([stringOptionalNullable, numberOptional])),
- gauge_inner_color: stringOptionalNullable,
- gauge_inner_width: stringOrNumberOptionalNullable,
- gauge_style: stringOptionalNullable,
- gauge_max: stringOrNumberOptionalNullable,
- id: stringRequired,
- ignore_global_filters: numberOptional,
- ignore_global_filter: numberOptional,
- index_pattern: stringRequired,
- interval: stringRequired,
- isModelInvalid: schema.maybe(schema.boolean()),
- legend_position: stringOptionalNullable,
- markdown: stringOptionalNullable,
- markdown_scrollbars: numberIntegerOptional,
- markdown_openLinksInNewTab: numberIntegerOptional,
- markdown_vertical_align: stringOptionalNullable,
- markdown_less: stringOptionalNullable,
- markdown_css: stringOptionalNullable,
- pivot_id: stringOptionalNullable,
- pivot_label: stringOptionalNullable,
- pivot_type: stringOptionalNullable,
- pivot_rows: stringOptionalNullable,
- series: schema.arrayOf(seriesItems),
- show_grid: numberIntegerRequired,
- show_legend: numberIntegerRequired,
- tooltip_mode: schema.maybe(
- schema.oneOf([schema.literal('show_all'), schema.literal('show_focused')])
- ),
- time_field: stringOptionalNullable,
- time_range_mode: stringOptionalNullable,
- type: stringRequired,
- })
- ),
+ panels: schema.arrayOf(panel),
// general
query: schema.nullable(schema.arrayOf(queryObject)),
state: schema.object({
diff --git a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.js b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx
similarity index 77%
rename from src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.js
rename to src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx
index 7afa71d6ba38..0fb3e80344e2 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx
@@ -18,51 +18,49 @@
*/
import React from 'react';
-import { expect } from 'chai';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
-import sinon from 'sinon';
import { AddDeleteButtons } from './add_delete_buttons';
describe('AddDeleteButtons', () => {
it('calls onAdd={handleAdd}', () => {
- const handleAdd = sinon.spy();
+ const handleAdd = jest.fn();
const wrapper = shallowWithIntl( );
wrapper.find('EuiButtonIcon').at(0).simulate('click');
- expect(handleAdd.calledOnce).to.equal(true);
+ expect(handleAdd).toHaveBeenCalled();
});
it('calls onDelete={handleDelete}', () => {
- const handleDelete = sinon.spy();
+ const handleDelete = jest.fn();
const wrapper = shallowWithIntl( );
wrapper.find('EuiButtonIcon').at(1).simulate('click');
- expect(handleDelete.calledOnce).to.equal(true);
+ expect(handleDelete).toHaveBeenCalled();
});
it('calls onClone={handleClone}', () => {
- const handleClone = sinon.spy();
+ const handleClone = jest.fn();
const wrapper = shallowWithIntl( );
wrapper.find('EuiButtonIcon').at(0).simulate('click');
- expect(handleClone.calledOnce).to.equal(true);
+ expect(handleClone).toHaveBeenCalled();
});
it('disableDelete={true}', () => {
const wrapper = shallowWithIntl( );
- expect(wrapper.find({ text: 'Delete' })).to.have.length(0);
+ expect(wrapper.find({ text: 'Delete' })).toHaveLength(0);
});
it('disableAdd={true}', () => {
const wrapper = shallowWithIntl( );
- expect(wrapper.find({ text: 'Add' })).to.have.length(0);
+ expect(wrapper.find({ text: 'Add' })).toHaveLength(0);
});
it('should not display clone by default', () => {
const wrapper = shallowWithIntl( );
- expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
+ expect(wrapper.find({ text: 'Clone' })).toHaveLength(0);
});
it('should not display clone when disableAdd={true}', () => {
- const fn = sinon.spy();
+ const fn = jest.fn();
const wrapper = shallowWithIntl( );
- expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
+ expect(wrapper.find({ text: 'Clone' })).toHaveLength(0);
});
});
diff --git a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.js b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx
similarity index 87%
rename from src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.js
rename to src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx
index 798d16947c3d..7502de1cb1aa 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx
@@ -17,13 +17,29 @@
* under the License.
*/
-import PropTypes from 'prop-types';
-import React from 'react';
-import { EuiToolTip, EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import React, { MouseEvent } from 'react';
+import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { isBoolean } from 'lodash';
-export function AddDeleteButtons(props) {
+interface AddDeleteButtonsProps {
+ addTooltip: string;
+ deleteTooltip: string;
+ cloneTooltip: string;
+ activatePanelTooltip: string;
+ deactivatePanelTooltip: string;
+ isPanelActive?: boolean;
+ disableAdd?: boolean;
+ disableDelete?: boolean;
+ responsive?: boolean;
+ testSubj: string;
+ togglePanelActivation?: () => void;
+ onClone?: () => void;
+ onAdd?: () => void;
+ onDelete?: (event: MouseEvent) => void;
+}
+
+export function AddDeleteButtons(props: AddDeleteButtonsProps) {
const { testSubj } = props;
const createDelete = () => {
if (props.disableDelete) {
@@ -147,19 +163,3 @@ AddDeleteButtons.defaultProps = {
}
),
};
-
-AddDeleteButtons.propTypes = {
- addTooltip: PropTypes.string,
- deleteTooltip: PropTypes.string,
- cloneTooltip: PropTypes.string,
- activatePanelTooltip: PropTypes.string,
- deactivatePanelTooltip: PropTypes.string,
- togglePanelActivation: PropTypes.func,
- isPanelActive: PropTypes.bool,
- disableAdd: PropTypes.bool,
- disableDelete: PropTypes.bool,
- onClone: PropTypes.func,
- onAdd: PropTypes.func,
- onDelete: PropTypes.func,
- responsive: PropTypes.bool,
-};
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx
similarity index 70%
rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg.js
rename to src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx
index d547f64f13f6..e5236c3833b1 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx
@@ -17,15 +17,33 @@
* under the License.
*/
-import PropTypes from 'prop-types';
-import React from 'react';
+import React, { HTMLAttributes } from 'react';
+// @ts-ignore
import { aggToComponent } from '../lib/agg_to_component';
+// @ts-ignore
+import { isMetricEnabled } from '../../lib/check_ui_restrictions';
import { UnsupportedAgg } from './unsupported_agg';
import { TemporaryUnsupportedAgg } from './temporary_unsupported_agg';
+import { MetricsItemsSchema, PanelSchema, SeriesItemsSchema } from '../../../../common/types';
+import { DragHandleProps } from '../../../types';
+import { TimeseriesUIRestrictions } from '../../../../common/ui_restrictions';
+import { IFieldType } from '../../../../../data/common/index_patterns/fields';
-import { isMetricEnabled } from '../../lib/check_ui_restrictions';
+interface AggProps extends HTMLAttributes {
+ disableDelete: boolean;
+ fields: IFieldType[];
+ model: MetricsItemsSchema;
+ panel: PanelSchema;
+ series: SeriesItemsSchema;
+ siblings: MetricsItemsSchema[];
+ uiRestrictions: TimeseriesUIRestrictions;
+ dragHandleProps: DragHandleProps;
+ onAdd: () => void;
+ onChange: () => void;
+ onDelete: () => void;
+}
-export function Agg(props) {
+export function Agg(props: AggProps) {
const { model, uiRestrictions } = props;
let Component = aggToComponent[model.type];
@@ -59,17 +77,3 @@ export function Agg(props) {
);
}
-
-Agg.propTypes = {
- disableDelete: PropTypes.bool,
- fields: PropTypes.object,
- model: PropTypes.object,
- onAdd: PropTypes.func,
- onChange: PropTypes.func,
- onDelete: PropTypes.func,
- panel: PropTypes.object,
- series: PropTypes.object,
- siblings: PropTypes.array,
- uiRestrictions: PropTypes.object,
- dragHandleProps: PropTypes.object,
-};
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx
similarity index 86%
rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.js
rename to src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx
index a2f1640904dd..0363ba486a77 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx
@@ -17,15 +17,26 @@
* under the License.
*/
-import PropTypes from 'prop-types';
import React from 'react';
import { last } from 'lodash';
-import { AddDeleteButtons } from '../add_delete_buttons';
import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-import { SeriesDragHandler } from '../series_drag_handler';
import { i18n } from '@kbn/i18n';
+import { AddDeleteButtons } from '../add_delete_buttons';
+import { SeriesDragHandler } from '../series_drag_handler';
+import { MetricsItemsSchema } from '../../../../common/types';
+import { DragHandleProps } from '../../../types';
-export function AggRow(props) {
+interface AggRowProps {
+ disableDelete: boolean;
+ model: MetricsItemsSchema;
+ siblings: MetricsItemsSchema[];
+ dragHandleProps: DragHandleProps;
+ children: React.ReactNode;
+ onAdd: () => void;
+ onDelete: () => void;
+}
+
+export function AggRow(props: AggRowProps) {
let iconType = 'eyeClosed';
let iconColor = 'subdued';
const lastSibling = last(props.siblings);
@@ -71,12 +82,3 @@ export function AggRow(props) {
);
}
-
-AggRow.propTypes = {
- disableDelete: PropTypes.bool,
- model: PropTypes.object,
- onAdd: PropTypes.func,
- onDelete: PropTypes.func,
- siblings: PropTypes.array,
- dragHandleProps: PropTypes.object,
-};
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx
similarity index 88%
rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.js
rename to src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx
index 7ff6b6eb5669..6fa1a2adaa08 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx
@@ -17,14 +17,17 @@
* under the License.
*/
-import PropTypes from 'prop-types';
import React from 'react';
-import { EuiComboBox } from '@elastic/eui';
+import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { injectI18n } from '@kbn/i18n/react';
+// @ts-ignore
import { isMetricEnabled } from '../../lib/check_ui_restrictions';
+import { MetricsItemsSchema } from '../../../../common/types';
+import { TimeseriesUIRestrictions } from '../../../../common/ui_restrictions';
-const metricAggs = [
+type AggSelectOption = EuiComboBoxOptionOption;
+
+const metricAggs: AggSelectOption[] = [
{
label: i18n.translate('visTypeTimeseries.aggSelect.metricsAggs.averageLabel', {
defaultMessage: 'Average',
@@ -123,7 +126,7 @@ const metricAggs = [
},
];
-const pipelineAggs = [
+const pipelineAggs: AggSelectOption[] = [
{
label: i18n.translate('visTypeTimeseries.aggSelect.pipelineAggs.bucketScriptLabel', {
defaultMessage: 'Bucket Script',
@@ -162,7 +165,7 @@ const pipelineAggs = [
},
];
-const siblingAggs = [
+const siblingAggs: AggSelectOption[] = [
{
label: i18n.translate('visTypeTimeseries.aggSelect.siblingAggs.overallAverageLabel', {
defaultMessage: 'Overall Average',
@@ -207,7 +210,7 @@ const siblingAggs = [
},
];
-const specialAggs = [
+const specialAggs: AggSelectOption[] = [
{
label: i18n.translate('visTypeTimeseries.aggSelect.specialAggs.seriesAggLabel', {
defaultMessage: 'Series Agg',
@@ -224,14 +227,23 @@ const specialAggs = [
const allAggOptions = [...metricAggs, ...pipelineAggs, ...siblingAggs, ...specialAggs];
-function filterByPanelType(panelType) {
- return (agg) => {
+function filterByPanelType(panelType: string) {
+ return (agg: AggSelectOption) => {
if (panelType === 'table') return agg.value !== 'series_agg';
return true;
};
}
-function AggSelectUi(props) {
+interface AggSelectUiProps {
+ id: string;
+ panelType: string;
+ siblings: MetricsItemsSchema[];
+ value: string;
+ uiRestrictions?: TimeseriesUIRestrictions;
+ onChange: (currentlySelectedOptions: AggSelectOption[]) => void;
+}
+
+export function AggSelect(props: AggSelectUiProps) {
const { siblings, panelType, value, onChange, uiRestrictions, ...rest } = props;
const selectedOptions = allAggOptions.filter((option) => {
@@ -242,11 +254,11 @@ function AggSelectUi(props) {
if (siblings.length <= 1) enablePipelines = false;
- let options;
+ let options: EuiComboBoxOptionOption[];
if (panelType === 'metrics') {
options = metricAggs;
} else {
- const disableSiblingAggs = (agg) => ({
+ const disableSiblingAggs = (agg: AggSelectOption) => ({
...agg,
disabled: !enablePipelines || !isMetricEnabled(agg.value, uiRestrictions),
});
@@ -282,9 +294,9 @@ function AggSelectUi(props) {
];
}
- const handleChange = (selectedOptions) => {
- if (!selectedOptions || selectedOptions.length <= 0) return;
- onChange(selectedOptions);
+ const handleChange = (currentlySelectedOptions: AggSelectOption[]) => {
+ if (!currentlySelectedOptions || currentlySelectedOptions.length <= 0) return;
+ onChange(currentlySelectedOptions);
};
return (
@@ -303,13 +315,3 @@ function AggSelectUi(props) {