+
+
+ {i18n.UPGRADE_TO_PLATINUM_SUBTITLE}
+
+
+
+
+
+
+ {i18n.UPGRADE_SUBSCRIPTION}
+
+ ,
+
+
+
+ {i18n.START_TRIAL}
+
+ ,
+
+
+
+
+ }
+ />
+ );
+});
+LicensePrompt.displayName = 'LicensePrompt';
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/index.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/index.tsx
index fa9b54122562d..ac6d0b5534b9a 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/index.tsx
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/index.tsx
@@ -26,9 +26,13 @@ import { MaintenanceWindowsList } from './components/maintenance_windows_list';
import { useFindMaintenanceWindows } from '../../hooks/use_find_maintenance_windows';
import { CenterJustifiedSpinner } from './components/center_justified_spinner';
import { ExperimentalBadge } from './components/page_header';
+import { useLicense } from '../../hooks/use_license';
+import { LicensePrompt } from './components/license_prompt';
export const MaintenanceWindowsPage = React.memo(() => {
const { docLinks } = useKibana().services;
+ const { isAtLeastPlatinum } = useLicense();
+
const { navigateToCreateMaintenanceWindow } = useCreateMaintenanceWindowNavigation();
const { isLoading, maintenanceWindows, refetch } = useFindMaintenanceWindows();
@@ -42,6 +46,7 @@ export const MaintenanceWindowsPage = React.memo(() => {
const refreshData = useCallback(() => refetch(), [refetch]);
const showEmptyPrompt = !isLoading && maintenanceWindows.length === 0;
+ const hasLicense = isAtLeastPlatinum();
if (isLoading) {
return ;
@@ -66,7 +71,7 @@ export const MaintenanceWindowsPage = React.memo(() => {
{i18n.MAINTENANCE_WINDOWS_DESCRIPTION}
- {!showEmptyPrompt ? (
+ {!showEmptyPrompt && hasLicense ? (
{i18n.CREATE_NEW_BUTTON}
@@ -74,7 +79,9 @@ export const MaintenanceWindowsPage = React.memo(() => {
) : null}
- {showEmptyPrompt ? (
+ {!hasLicense ? (
+
+ ) : showEmptyPrompt ? (
) : (
<>
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts
index 65f24411a2a1a..7e0c2fa484f7a 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts
@@ -568,3 +568,31 @@ export const EXPERIMENTAL_DESCRIPTION = i18n.translate(
export const UPCOMING = i18n.translate('xpack.alerting.maintenanceWindows.upcoming', {
defaultMessage: 'Upcoming',
});
+
+export const UPGRADE_TO_PLATINUM = i18n.translate(
+ 'xpack.alerting.maintenanceWindows.licenseCallout.updgradeToPlatinumTitle',
+ {
+ defaultMessage: 'Maintenance Windows are a subscription feature.',
+ }
+);
+
+export const UPGRADE_TO_PLATINUM_SUBTITLE = i18n.translate(
+ 'xpack.alerting.maintenanceWindows.licenseCallout.upgradeToPlatinumSubtitle',
+ {
+ defaultMessage: 'Select an option to unlock it.',
+ }
+);
+
+export const UPGRADE_SUBSCRIPTION = i18n.translate(
+ 'xpack.alerting.maintenanceWindows.licenseCallout.upgradeSubscription',
+ {
+ defaultMessage: 'Upgrade subscription',
+ }
+);
+
+export const START_TRIAL = i18n.translate(
+ 'xpack.alerting.maintenanceWindows.licenseCallout.startTrial',
+ {
+ defaultMessage: 'Start trial',
+ }
+);
diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts
index bfd7f1c19e376..d13bc2e708efe 100644
--- a/x-pack/plugins/apm/server/index.ts
+++ b/x-pack/plugins/apm/server/index.ts
@@ -56,6 +56,7 @@ const configSchema = schema.object({
latestAgentVersionsUrl: schema.string({
defaultValue: 'https://apm-agent-versions.elastic.co/versions.json',
}),
+ enabled: schema.boolean({ defaultValue: true }),
});
// plugin config
diff --git a/x-pack/plugins/cross_cluster_replication/server/config.ts b/x-pack/plugins/cross_cluster_replication/server/config.ts
index bac5f917f22a6..4cba6d0707abb 100644
--- a/x-pack/plugins/cross_cluster_replication/server/config.ts
+++ b/x-pack/plugins/cross_cluster_replication/server/config.ts
@@ -22,6 +22,11 @@ const schemaLatest = schema.object(
ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
+ /**
+ * Disables the plugin.
+ * Added back in 8.8.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
},
{ defaultValue: undefined }
);
diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts
index 5cfd5e7029459..9c1b0575694c4 100644
--- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts
@@ -24,13 +24,13 @@ export const mockKibanaValues = {
),
} as unknown as ApplicationStart,
capabilities: {} as Capabilities,
- config: { host: 'http://localhost:3002' },
charts: chartPluginMock.createStartContract(),
cloud: {
...cloudMock.createSetup(),
- isCloudEnabled: false,
deployment_url: 'https://cloud.elastic.co/deployments/some-id',
+ isCloudEnabled: false,
},
+ config: { host: 'http://localhost:3002' },
data: dataPluginMock.createStartContract(),
guidedOnboarding: {},
history: mockHistory,
@@ -50,12 +50,12 @@ export const mockKibanaValues = {
hasNativeConnectors: true,
hasWebCrawler: true,
},
- uiSettings: uiSettingsServiceMock.createStartContract(),
+ renderHeaderActions: jest.fn(),
security: securityMock.createStart(),
setBreadcrumbs: jest.fn(),
setChromeIsVisible: jest.fn(),
setDocTitle: jest.fn(),
- renderHeaderActions: jest.fn(),
+ uiSettings: uiSettingsServiceMock.createStartContract(),
};
jest.mock('../../shared/kibana', () => ({
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts
index 2a400ce2d0269..b7d264ba43e99 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts
@@ -67,9 +67,9 @@ export const KibanaLogic = kea>({
reducers: ({ props }) => ({
application: [props.application || {}, {}],
capabilities: [props.capabilities || {}, {}],
- config: [props.config || {}, {}],
charts: [props.charts, {}],
cloud: [props.cloud || {}, {}],
+ config: [props.config || {}, {}],
data: [props.data, {}],
guidedOnboarding: [props.guidedOnboarding, {}],
history: [props.history, {}],
diff --git a/x-pack/plugins/enterprise_search/server/index.ts b/x-pack/plugins/enterprise_search/server/index.ts
index 19019841976d4..b4c86696c4858 100644
--- a/x-pack/plugins/enterprise_search/server/index.ts
+++ b/x-pack/plugins/enterprise_search/server/index.ts
@@ -19,6 +19,7 @@ export const configSchema = schema.object({
accessCheckTimeoutWarning: schema.number({ defaultValue: 300 }),
canDeployEntSearch: schema.boolean({ defaultValue: true }),
customHeaders: schema.maybe(schema.object({}, { unknowns: 'allow' })),
+ enabled: schema.boolean({ defaultValue: true }),
hasConnectors: schema.boolean({ defaultValue: true }),
hasDefaultIngestPipeline: schema.boolean({ defaultValue: true }),
hasNativeConnectors: schema.boolean({ defaultValue: true }),
diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts
index 92977df6021d6..4875c7872a20c 100644
--- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts
@@ -166,6 +166,12 @@ describe('Enterprise Search Managed Indices', () => {
mockTrainedModelsProvider = {
getTrainedModels: jest.fn(),
getTrainedModelsStats: jest.fn(),
+ startTrainedModelDeployment: jest.fn(),
+ stopTrainedModelDeployment: jest.fn(),
+ inferTrainedModel: jest.fn(),
+ deleteTrainedModel: jest.fn(),
+ updateTrainedModelDeployment: jest.fn(),
+ putTrainedModel: jest.fn(),
} as MlTrainedModels;
mockMl = {
@@ -1060,6 +1066,12 @@ describe('Enterprise Search Managed Indices', () => {
mockTrainedModelsProvider = {
getTrainedModels: jest.fn(),
getTrainedModelsStats: jest.fn(),
+ startTrainedModelDeployment: jest.fn(),
+ stopTrainedModelDeployment: jest.fn(),
+ inferTrainedModel: jest.fn(),
+ deleteTrainedModel: jest.fn(),
+ updateTrainedModelDeployment: jest.fn(),
+ putTrainedModel: jest.fn(),
} as MlTrainedModels;
mockMl = {
diff --git a/x-pack/plugins/fleet/common/authz.ts b/x-pack/plugins/fleet/common/authz.ts
index 83d337c00368b..3fbfd614d8038 100644
--- a/x-pack/plugins/fleet/common/authz.ts
+++ b/x-pack/plugins/fleet/common/authz.ts
@@ -107,7 +107,7 @@ export function calculatePackagePrivilegesFromCapabilities(
return {
...acc,
[privilege]: {
- executePackageAction: capabilities.siem[privilegeName] || false,
+ executePackageAction: (capabilities.siem && capabilities.siem[privilegeName]) || false,
},
};
},
diff --git a/x-pack/plugins/fleet/common/openapi/README.md b/x-pack/plugins/fleet/common/openapi/README.md
index 3dc43c18785a0..e5241e3b27872 100644
--- a/x-pack/plugins/fleet/common/openapi/README.md
+++ b/x-pack/plugins/fleet/common/openapi/README.md
@@ -1,6 +1,4 @@
-# OpenAPI (Experimental)
-
-> **_NOTE:_** This spec is experimental and may be incomplete or change later.
+# OpenAPI
The current self-contained spec file, available [as JSON](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/fleet/common/openapi/bundled.json) or [as YAML](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/fleet/common/openapi/bundled.yaml), can be used for online tools like those found at https://openapi.tools/.
@@ -8,6 +6,8 @@ For example, [click here to view the specification in the Swagger UI](https://pe
A guide about the openApi specification can be found at [https://swagger.io/docs/specification/about/](https://swagger.io/docs/specification/about/).
+Fleet API docs: https://www.elastic.co/guide/en/fleet/master/fleet-apis.html
+
## The `openapi` folder
- `entrypoint.yaml` is the overview file which links to the various files on disk.
diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts
index 267d9873aaa2d..a370c0825664c 100644
--- a/x-pack/plugins/fleet/server/config.ts
+++ b/x-pack/plugins/fleet/server/config.ts
@@ -166,6 +166,7 @@ export const config: PluginConfigDescriptor = {
}),
})
),
+ enabled: schema.boolean({ defaultValue: true }),
}),
};
diff --git a/x-pack/plugins/index_lifecycle_management/server/config.ts b/x-pack/plugins/index_lifecycle_management/server/config.ts
index 737cc6a472c7a..7fdec20bbb050 100644
--- a/x-pack/plugins/index_lifecycle_management/server/config.ts
+++ b/x-pack/plugins/index_lifecycle_management/server/config.ts
@@ -24,6 +24,11 @@ const schemaLatest = schema.object(
}),
// Cloud requires the ability to hide internal node attributes from users.
filteredNodeAttributes: schema.arrayOf(schema.string(), { defaultValue: [] }),
+ /**
+ * Disables the plugin.
+ * Added back in 8.8.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
},
{ defaultValue: undefined }
);
diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx
index ef515cc018839..2ae8d8743b37d 100644
--- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx
@@ -16,7 +16,6 @@ import {
EuiFlexItem,
} from '@elastic/eui';
import { css } from '@emotion/react';
-import { METRICS_APP_DATA_TEST_SUBJ } from '../../../../../apps/metrics_app';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
import { ControlsContent } from './controls_content';
@@ -101,7 +100,7 @@ const StickyContainer = (props: { children: React.ReactNode }) => {
const { euiTheme } = useEuiTheme();
const top = useMemo(() => {
- const wrapper = document.querySelector(`[data-test-subj="${METRICS_APP_DATA_TEST_SUBJ}"]`);
+ const wrapper = document.querySelector(`[data-test-subj="kibanaChrome"]`);
if (!wrapper) {
return `calc(${euiTheme.size.xxxl} * 2)`;
}
diff --git a/x-pack/plugins/license_management/server/config.ts b/x-pack/plugins/license_management/server/config.ts
index 42beba0ea5c09..23449bc19e793 100644
--- a/x-pack/plugins/license_management/server/config.ts
+++ b/x-pack/plugins/license_management/server/config.ts
@@ -22,6 +22,11 @@ const schemaLatest = schema.object(
ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
+ /**
+ * Disables the plugin.
+ * Added back in 8.8.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
},
{ defaultValue: undefined }
);
diff --git a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts
index a547ef9c6d93a..b14efda88cad4 100644
--- a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts
+++ b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts
@@ -16,7 +16,7 @@ import {
VectorStyleDescriptor,
} from './style_property_descriptor_types';
import { DataRequestDescriptor } from './data_request_descriptor_types';
-import { AbstractSourceDescriptor, TermJoinSourceDescriptor } from './source_descriptor_types';
+import { AbstractSourceDescriptor, JoinSourceDescriptor } from './source_descriptor_types';
import { LAYER_TYPE } from '../constants';
export type Attribution = {
@@ -26,7 +26,7 @@ export type Attribution = {
export type JoinDescriptor = {
leftField?: string;
- right: TermJoinSourceDescriptor;
+ right: JoinSourceDescriptor;
};
export type TileMetaFeature = Feature & {
diff --git a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts
index c76bc8f6a6e17..1dabde9bc0a64 100644
--- a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts
+++ b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts
@@ -183,4 +183,4 @@ export type TableSourceDescriptor = {
term: string;
};
-export type TermJoinSourceDescriptor = ESTermSourceDescriptor | TableSourceDescriptor;
+export type JoinSourceDescriptor = ESTermSourceDescriptor | TableSourceDescriptor;
diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.test.js b/x-pack/plugins/maps/public/classes/joins/inner_join.test.ts
similarity index 68%
rename from x-pack/plugins/maps/public/classes/joins/inner_join.test.js
rename to x-pack/plugins/maps/public/classes/joins/inner_join.test.ts
index b01d977972a68..160ced8f46b9d 100644
--- a/x-pack/plugins/maps/public/classes/joins/inner_join.test.js
+++ b/x-pack/plugins/maps/public/classes/joins/inner_join.test.ts
@@ -5,8 +5,15 @@
* 2.0.
*/
-import { createJoinTermSource, InnerJoin } from './inner_join';
-import { SOURCE_TYPES } from '../../../common/constants';
+import type { Feature } from 'geojson';
+import type {
+ ESTermSourceDescriptor,
+ JoinSourceDescriptor,
+} from '../../../common/descriptor_types';
+import type { IVectorSource } from '../sources/vector_source';
+import type { IField } from '../fields/field';
+import { createJoinSource, InnerJoin } from './inner_join';
+import { AGG_TYPE, SOURCE_TYPES } from '../../../common/constants';
jest.mock('../../kibana_services', () => {});
jest.mock('../layers/vector_layer', () => {});
@@ -16,20 +23,20 @@ const rightSource = {
id: 'd3625663-5b34-4d50-a784-0d743f676a0c',
indexPatternId: '90943e30-9a47-11e8-b64d-95841ca0b247',
term: 'geo.dest',
- metrics: [{ type: 'count' }],
-};
+ metrics: [{ type: AGG_TYPE.COUNT }],
+} as ESTermSourceDescriptor;
const mockSource = {
- createField({ fieldName: name }) {
+ createField({ fieldName }: { fieldName: string }) {
return {
getName() {
- return name;
+ return fieldName;
},
- };
+ } as unknown as IField;
},
-};
+} as unknown as IVectorSource;
-const leftJoin = new InnerJoin(
+const iso2LeftJoin = new InnerJoin(
{
leftField: 'iso2',
right: rightSource,
@@ -38,27 +45,27 @@ const leftJoin = new InnerJoin(
);
const COUNT_PROPERTY_NAME = '__kbnjoin__count__d3625663-5b34-4d50-a784-0d743f676a0c';
-describe('createJoinTermSource', () => {
+describe('createJoinSource', () => {
test('Should return undefined when descriptor is not provided', () => {
- expect(createJoinTermSource(undefined)).toBe(undefined);
+ expect(createJoinSource(undefined)).toBe(undefined);
});
test('Should return undefined with unmatched source type', () => {
expect(
- createJoinTermSource({
+ createJoinSource({
type: SOURCE_TYPES.WMS,
- })
+ } as unknown as Partial)
).toBe(undefined);
});
describe('EsTermSource', () => {
test('Should return EsTermSource', () => {
- expect(createJoinTermSource(rightSource).constructor.name).toBe('ESTermSource');
+ expect(createJoinSource(rightSource)?.constructor.name).toBe('ESTermSource');
});
test('Should return undefined when indexPatternId is undefined', () => {
expect(
- createJoinTermSource({
+ createJoinSource({
...rightSource,
indexPatternId: undefined,
})
@@ -67,7 +74,7 @@ describe('createJoinTermSource', () => {
test('Should return undefined when term is undefined', () => {
expect(
- createJoinTermSource({
+ createJoinSource({
...rightSource,
term: undefined,
})
@@ -78,9 +85,9 @@ describe('createJoinTermSource', () => {
describe('TableSource', () => {
test('Should return TableSource', () => {
expect(
- createJoinTermSource({
+ createJoinSource({
type: SOURCE_TYPES.TABLE_SOURCE,
- }).constructor.name
+ })?.constructor.name
).toBe('TableSource');
});
});
@@ -92,15 +99,11 @@ describe('joinPropertiesToFeature', () => {
properties: {
iso2: 'CN',
},
- };
+ } as unknown as Feature;
const propertiesMap = new Map();
propertiesMap.set('CN', { [COUNT_PROPERTY_NAME]: 61 });
- leftJoin.joinPropertiesToFeature(feature, propertiesMap, [
- {
- propertyKey: COUNT_PROPERTY_NAME,
- },
- ]);
+ iso2LeftJoin.joinPropertiesToFeature(feature, propertiesMap);
expect(feature.properties).toEqual({
iso2: 'CN',
[COUNT_PROPERTY_NAME]: 61,
@@ -114,21 +117,17 @@ describe('joinPropertiesToFeature', () => {
[COUNT_PROPERTY_NAME]: 61,
[`__kbn__dynamic__${COUNT_PROPERTY_NAME}__fillColor`]: 1,
},
- };
+ } as unknown as Feature;
const propertiesMap = new Map();
- leftJoin.joinPropertiesToFeature(feature, propertiesMap, [
- {
- propertyKey: COUNT_PROPERTY_NAME,
- },
- ]);
+ iso2LeftJoin.joinPropertiesToFeature(feature, propertiesMap);
expect(feature.properties).toEqual({
iso2: 'CN',
});
});
test('Should coerce to string before joining', () => {
- const leftJoin = new InnerJoin(
+ const zipCodeLeftJoin = new InnerJoin(
{
leftField: 'zipcode',
right: rightSource,
@@ -140,15 +139,11 @@ describe('joinPropertiesToFeature', () => {
properties: {
zipcode: 40204,
},
- };
+ } as unknown as Feature;
const propertiesMap = new Map();
propertiesMap.set('40204', { [COUNT_PROPERTY_NAME]: 61 });
- leftJoin.joinPropertiesToFeature(feature, propertiesMap, [
- {
- propertyKey: COUNT_PROPERTY_NAME,
- },
- ]);
+ zipCodeLeftJoin.joinPropertiesToFeature(feature, propertiesMap);
expect(feature.properties).toEqual({
zipcode: 40204,
[COUNT_PROPERTY_NAME]: 61,
@@ -157,26 +152,22 @@ describe('joinPropertiesToFeature', () => {
test('Should handle undefined values', () => {
const feature = {
- //this feature does not have the iso2 field
+ // this feature does not have the iso2 field
properties: {
zipcode: 40204,
},
- };
+ } as unknown as Feature;
const propertiesMap = new Map();
propertiesMap.set('40204', { [COUNT_PROPERTY_NAME]: 61 });
- leftJoin.joinPropertiesToFeature(feature, propertiesMap, [
- {
- propertyKey: COUNT_PROPERTY_NAME,
- },
- ]);
+ iso2LeftJoin.joinPropertiesToFeature(feature, propertiesMap);
expect(feature.properties).toEqual({
zipcode: 40204,
});
});
test('Should handle falsy values', () => {
- const leftJoin = new InnerJoin(
+ const codeLeftJoin = new InnerJoin(
{
leftField: 'code',
right: rightSource,
@@ -188,15 +179,11 @@ describe('joinPropertiesToFeature', () => {
properties: {
code: 0,
},
- };
+ } as unknown as Feature;
const propertiesMap = new Map();
propertiesMap.set('0', { [COUNT_PROPERTY_NAME]: 61 });
- leftJoin.joinPropertiesToFeature(feature, propertiesMap, [
- {
- propertyKey: COUNT_PROPERTY_NAME,
- },
- ]);
+ codeLeftJoin.joinPropertiesToFeature(feature, propertiesMap);
expect(feature.properties).toEqual({
code: 0,
[COUNT_PROPERTY_NAME]: 61,
diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.ts b/x-pack/plugins/maps/public/classes/joins/inner_join.ts
index a754650cdef80..6ac9a674efc8d 100644
--- a/x-pack/plugins/maps/public/classes/joins/inner_join.ts
+++ b/x-pack/plugins/maps/public/classes/joins/inner_join.ts
@@ -8,7 +8,6 @@
import type { KibanaExecutionContext } from '@kbn/core/public';
import type { Query } from '@kbn/es-query';
import { Feature, GeoJsonProperties } from 'geojson';
-import { ESTermSource } from '../sources/es_term_source';
import { getComputedFieldNamePrefix } from '../styles/vector/style_util';
import {
FORMATTERS_DATA_REQUEST_ID_SUFFIX,
@@ -18,18 +17,18 @@ import {
import {
ESTermSourceDescriptor,
JoinDescriptor,
+ JoinSourceDescriptor,
TableSourceDescriptor,
- TermJoinSourceDescriptor,
} from '../../../common/descriptor_types';
import { IVectorSource } from '../sources/vector_source';
import { IField } from '../fields/field';
import { PropertiesMap } from '../../../common/elasticsearch_util';
-import { ITermJoinSource } from '../sources/term_join_source';
-import { TableSource } from '../sources/table_source';
+import { IJoinSource } from '../sources/join_sources';
+import { ESTermSource, TableSource } from '../sources/join_sources';
-export function createJoinTermSource(
- descriptor: Partial | undefined
-): ITermJoinSource | undefined {
+export function createJoinSource(
+ descriptor: Partial | undefined
+): IJoinSource | undefined {
if (!descriptor) {
return;
}
@@ -47,12 +46,12 @@ export function createJoinTermSource(
export class InnerJoin {
private readonly _descriptor: JoinDescriptor;
- private readonly _rightSource?: ITermJoinSource;
+ private readonly _rightSource?: IJoinSource;
private readonly _leftField?: IField;
constructor(joinDescriptor: JoinDescriptor, leftSource: IVectorSource) {
this._descriptor = joinDescriptor;
- this._rightSource = createJoinTermSource(this._descriptor.right);
+ this._rightSource = createJoinSource(this._descriptor.right);
this._leftField = joinDescriptor.leftField
? leftSource.createField({ fieldName: joinDescriptor.leftField })
: undefined;
@@ -127,7 +126,7 @@ export class InnerJoin {
return joinKey === undefined || joinKey === null ? null : joinKey.toString();
}
- getRightJoinSource(): ITermJoinSource {
+ getRightJoinSource(): IJoinSource {
if (!this._rightSource) {
throw new Error('Cannot get rightSource from InnerJoin with incomplete config');
}
diff --git a/x-pack/plugins/maps/public/classes/layers/build_vector_request_meta.ts b/x-pack/plugins/maps/public/classes/layers/build_vector_request_meta.ts
index e0df7ab8d6dd5..adb53e76c060a 100644
--- a/x-pack/plugins/maps/public/classes/layers/build_vector_request_meta.ts
+++ b/x-pack/plugins/maps/public/classes/layers/build_vector_request_meta.ts
@@ -9,10 +9,10 @@ import _ from 'lodash';
import type { Query } from '@kbn/data-plugin/common';
import { DataFilters, VectorSourceRequestMeta } from '../../../common/descriptor_types';
import { IVectorSource } from '../sources/vector_source';
-import { ITermJoinSource } from '../sources/term_join_source';
+import { IJoinSource } from '../sources/join_sources';
export function buildVectorRequestMeta(
- source: IVectorSource | ITermJoinSource,
+ source: IVectorSource | IJoinSource,
fieldNames: string[],
dataFilters: DataFilters,
sourceQuery: Query | null | undefined,
diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts
index 8640dbc5954aa..8a4f3e575d1c9 100644
--- a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts
+++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts
@@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
import { FEATURE_VISIBLE_PROPERTY_NAME } from '../../../../../common/constants';
import { DataRequestContext } from '../../../../actions';
import { JoinState } from '../types';
+import { isTermJoinSource, type ITermJoinSource } from '../../../sources/join_sources';
interface SourceResult {
refreshed: boolean;
@@ -77,13 +78,22 @@ export async function performInnerJoins(
updateSourceData({ ...sourceResult.featureCollection });
}
- const joinStatusesWithoutAnyMatches = joinStatuses.filter((joinStatus) => {
+ //
+ // term joins are easy to misconfigure.
+ // Users often are unaware of left values and right values and whether they allign for joining
+ // Provide messaging that helps users debug term joins with no matches
+ //
+ const termJoinStatusesWithoutAnyMatches = joinStatuses.filter((joinStatus) => {
+ if (!isTermJoinSource(joinStatus.joinState.join.getRightJoinSource())) {
+ return false;
+ }
+
const hasTerms =
joinStatus.joinState.propertiesMap && joinStatus.joinState.propertiesMap.size > 0;
return !joinStatus.joinedWithAtLeastOneFeature && hasTerms;
});
- if (joinStatusesWithoutAnyMatches.length) {
+ if (termJoinStatusesWithoutAnyMatches.length) {
function prettyPrintArray(array: unknown[]) {
return array.length <= 5
? array.join(',')
@@ -94,12 +104,10 @@ export async function performInnerJoins(
});
}
- const joinStatus = joinStatusesWithoutAnyMatches[0];
+ const joinStatus = termJoinStatusesWithoutAnyMatches[0];
const leftFieldName = await joinStatus.joinState.join.getLeftField().getLabel();
- const rightFieldName = await joinStatus.joinState.join
- .getRightJoinSource()
- .getTermField()
- .getLabel();
+ const termJoinSource = joinStatus.joinState.join.getRightJoinSource() as ITermJoinSource;
+ const rightFieldName = await termJoinSource.getTermField().getLabel();
const reason =
joinStatus.keys.length === 0
? i18n.translate('xpack.maps.vectorLayer.joinError.noLeftFieldValuesMsg', {
diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx
index 82bb15c19ffca..dab086b86b472 100644
--- a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx
+++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.test.tsx
@@ -25,7 +25,7 @@ import {
} from '../../../../../common/descriptor_types';
import { LAYER_TYPE, SOURCE_TYPES } from '../../../../../common/constants';
import { MvtVectorLayer } from './mvt_vector_layer';
-import { ITermJoinSource } from '../../../sources/term_join_source';
+import { IJoinSource } from '../../../sources/join_sources';
const defaultConfig = {
urlTemplate: 'https://example.com/{x}/{y}/{z}.pbf',
@@ -178,7 +178,7 @@ describe('isLayerLoading', () => {
return 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2';
},
getRightJoinSource: () => {
- return {} as unknown as ITermJoinSource;
+ return {} as unknown as IJoinSource;
},
} as unknown as InnerJoin,
],
@@ -217,7 +217,7 @@ describe('isLayerLoading', () => {
return 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2';
},
getRightJoinSource: () => {
- return {} as unknown as ITermJoinSource;
+ return {} as unknown as IJoinSource;
},
} as unknown as InnerJoin,
],
diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx
index 366c9cde6eee6..a18f525e66ae0 100644
--- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx
+++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx
@@ -27,7 +27,7 @@ import {
STYLE_TYPE,
VECTOR_STYLES,
} from '../../../../common/constants';
-import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property';
+import { TermJoinTooltipProperty } from '../../tooltips/term_join_tooltip_property';
import { DataRequestAbortError } from '../../util/data_request';
import { canSkipStyleMetaUpdate, canSkipFormattersUpdate } from '../../util/can_skip_fetch';
import {
@@ -57,7 +57,8 @@ import { DataRequestContext } from '../../../actions';
import { ITooltipProperty } from '../../tooltips/tooltip_property';
import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property';
import { IESSource } from '../../sources/es_source';
-import { ITermJoinSource } from '../../sources/term_join_source';
+import type { IJoinSource, ITermJoinSource } from '../../sources/join_sources';
+import { isTermJoinSource } from '../../sources/join_sources';
import type { IESAggSource } from '../../sources/es_agg_source';
import { buildVectorRequestMeta } from '../build_vector_request_meta';
import { getJoinAggKey } from '../../../../common/get_agg_key';
@@ -430,7 +431,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer {
}: {
dataRequestId: string;
dynamicStyleProps: Array>;
- source: IVectorSource | ITermJoinSource;
+ source: IVectorSource | IJoinSource;
sourceQuery?: Query;
style: IVectorStyle;
} & DataRequestContext) {
@@ -511,7 +512,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer {
}: {
dataRequestId: string;
fields: IField[];
- source: IVectorSource | ITermJoinSource;
+ source: IVectorSource | IJoinSource;
} & DataRequestContext) {
if (fields.length === 0) {
return;
@@ -983,17 +984,28 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer {
return this.getId() === mbSourceId;
}
+ /*
+ * Replaces source property tooltips with join property tooltips
+ * join property tooltips allow tooltips to
+ * 1) Create filter from right source context
+ * 2) Display tooltip with right source context
+ */
_addJoinsToSourceTooltips(tooltipsFromSource: ITooltipProperty[]) {
for (let i = 0; i < tooltipsFromSource.length; i++) {
const tooltipProperty = tooltipsFromSource[i];
- const matchingJoins = [];
+ const matchingTermJoins: ITermJoinSource[] = [];
for (let j = 0; j < this.getJoins().length; j++) {
- if (this.getJoins()[j].getLeftField().getName() === tooltipProperty.getPropertyKey()) {
- matchingJoins.push(this.getJoins()[j]);
+ const join = this.getJoins()[j];
+ const joinRightSource = join.getRightJoinSource();
+ if (
+ isTermJoinSource(joinRightSource) &&
+ this.getJoins()[j].getLeftField().getName() === tooltipProperty.getPropertyKey()
+ ) {
+ matchingTermJoins.push(joinRightSource as ITermJoinSource);
}
}
- if (matchingJoins.length) {
- tooltipsFromSource[i] = new JoinTooltipProperty(tooltipProperty, matchingJoins);
+ if (matchingTermJoins.length) {
+ tooltipsFromSource[i] = new TermJoinTooltipProperty(tooltipProperty, matchingTermJoins);
}
}
}
diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.test.ts
similarity index 86%
rename from x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js
rename to x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.test.ts
index 173ee5bff725f..dc93153c7c411 100644
--- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js
+++ b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.test.ts
@@ -5,25 +5,27 @@
* 2.0.
*/
+import { AGG_TYPE } from '../../../../../common/constants';
+import type { BucketProperties, PropertiesMap } from '../../../../../common/elasticsearch_util';
import { ESTermSource, extractPropertiesMap } from './es_term_source';
-jest.mock('../../layers/vector_layer', () => {});
+jest.mock('../../../layers/vector_layer', () => {});
const termFieldName = 'myTermField';
const sumFieldName = 'myFieldGettingSummed';
const metricExamples = [
{
- type: 'sum',
+ type: AGG_TYPE.SUM,
field: sumFieldName,
label: 'my custom label',
},
{
// metric config is invalid beause field is missing
- type: 'max',
+ type: AGG_TYPE.MAX,
},
{
// metric config is valid because "count" metric does not need to provide field
- type: 'count',
+ type: AGG_TYPE.COUNT,
label: '', // should ignore empty label fields
},
];
@@ -81,7 +83,7 @@ describe('extractPropertiesMap', () => {
};
const countPropName = '__kbnjoin__count__1234';
- let propertiesMap;
+ let propertiesMap: PropertiesMap = new Map();
beforeAll(() => {
propertiesMap = extractPropertiesMap(responseWithNumberTypes, countPropName);
});
@@ -93,17 +95,17 @@ describe('extractPropertiesMap', () => {
it('should extract count property', () => {
const properties = propertiesMap.get('109');
- expect(properties[countPropName]).toBe(1130);
+ expect(properties?.[countPropName]).toBe(1130);
});
it('should extract min property', () => {
const properties = propertiesMap.get('109');
- expect(properties[minPropName]).toBe(36);
+ expect(properties?.[minPropName]).toBe(36);
});
it('should extract property with value of "0"', () => {
const properties = propertiesMap.get('62');
- expect(properties[minPropName]).toBe(0);
+ expect(properties?.[minPropName]).toBe(0);
});
});
diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts
similarity index 88%
rename from x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts
index 4c7793e1b01cb..54ca553035574 100644
--- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts
+++ b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts
@@ -14,26 +14,26 @@ import {
DEFAULT_MAX_BUCKETS_LIMIT,
FIELD_ORIGIN,
SOURCE_TYPES,
-} from '../../../../common/constants';
-import { getJoinAggKey } from '../../../../common/get_agg_key';
-import { ESDocField } from '../../fields/es_doc_field';
-import { AbstractESAggSource } from '../es_agg_source';
+} from '../../../../../common/constants';
+import { getJoinAggKey } from '../../../../../common/get_agg_key';
+import { ESDocField } from '../../../fields/es_doc_field';
+import { AbstractESAggSource } from '../../es_agg_source';
import {
getField,
addFieldToDSL,
extractPropertiesFromBucket,
BucketProperties,
-} from '../../../../common/elasticsearch_util';
+} from '../../../../../common/elasticsearch_util';
import {
ESTermSourceDescriptor,
VectorSourceRequestMeta,
-} from '../../../../common/descriptor_types';
-import { PropertiesMap } from '../../../../common/elasticsearch_util';
-import { isValidStringConfig } from '../../util/valid_string_config';
-import { ITermJoinSource } from '../term_join_source';
-import type { IESAggSource } from '../es_agg_source';
-import { IField } from '../../fields/field';
-import { mergeExecutionContext } from '../execution_context_utils';
+} from '../../../../../common/descriptor_types';
+import { PropertiesMap } from '../../../../../common/elasticsearch_util';
+import { isValidStringConfig } from '../../../util/valid_string_config';
+import { ITermJoinSource } from '../types';
+import type { IESAggSource } from '../../es_agg_source';
+import { IField } from '../../../fields/field';
+import { mergeExecutionContext } from '../../execution_context_utils';
const TERMS_AGG_NAME = 'join';
const TERMS_BUCKET_KEYS_TO_IGNORE = ['key', 'doc_count'];
@@ -71,7 +71,7 @@ export class ESTermSource extends AbstractESAggSource implements ITermJoinSource
private readonly _termField: ESDocField;
readonly _descriptor: ESTermSourceDescriptor;
- constructor(descriptor: ESTermSourceDescriptor) {
+ constructor(descriptor: Partial) {
const sourceDescriptor = ESTermSource.createDescriptor(descriptor);
super(sourceDescriptor);
this._descriptor = sourceDescriptor;
diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/index.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/index.ts
similarity index 100%
rename from x-pack/plugins/maps/public/classes/sources/es_term_source/index.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/index.ts
diff --git a/x-pack/plugins/maps/public/classes/sources/term_join_source/index.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/index.ts
similarity index 55%
rename from x-pack/plugins/maps/public/classes/sources/term_join_source/index.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/index.ts
index 78f7705104f73..c916b2befca41 100644
--- a/x-pack/plugins/maps/public/classes/sources/term_join_source/index.ts
+++ b/x-pack/plugins/maps/public/classes/sources/join_sources/index.ts
@@ -5,4 +5,8 @@
* 2.0.
*/
-export type { ITermJoinSource } from './term_join_source';
+export type { IJoinSource, ITermJoinSource } from './types';
+
+export { isTermJoinSource } from './types';
+export { ESTermSource } from './es_term_source';
+export { TableSource } from './table_source';
diff --git a/x-pack/plugins/maps/public/classes/sources/table_source/index.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/index.ts
similarity index 100%
rename from x-pack/plugins/maps/public/classes/sources/table_source/index.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/table_source/index.ts
diff --git a/x-pack/plugins/maps/public/classes/sources/table_source/table_source.test.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts
similarity index 97%
rename from x-pack/plugins/maps/public/classes/sources/table_source/table_source.test.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts
index e43d3de268d31..df9c11a99daa4 100644
--- a/x-pack/plugins/maps/public/classes/sources/table_source/table_source.test.ts
+++ b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts
@@ -6,8 +6,8 @@
*/
import { TableSource } from './table_source';
-import { FIELD_ORIGIN } from '../../../../common/constants';
-import { VectorSourceRequestMeta } from '../../../../common/descriptor_types';
+import { FIELD_ORIGIN } from '../../../../../common/constants';
+import { VectorSourceRequestMeta } from '../../../../../common/descriptor_types';
describe('TableSource', () => {
describe('getName', () => {
diff --git a/x-pack/plugins/maps/public/classes/sources/table_source/table_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts
similarity index 92%
rename from x-pack/plugins/maps/public/classes/sources/table_source/table_source.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts
index 0bfdbc90be847..ed3015dca17e4 100644
--- a/x-pack/plugins/maps/public/classes/sources/table_source/table_source.ts
+++ b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts
@@ -8,25 +8,25 @@
import { v4 as uuidv4 } from 'uuid';
import { GeoJsonProperties } from 'geojson';
import type { Query } from '@kbn/data-plugin/common';
-import { FIELD_ORIGIN, SOURCE_TYPES, VECTOR_SHAPE_TYPE } from '../../../../common/constants';
+import { FIELD_ORIGIN, SOURCE_TYPES, VECTOR_SHAPE_TYPE } from '../../../../../common/constants';
import {
MapExtent,
TableSourceDescriptor,
VectorSourceRequestMeta,
-} from '../../../../common/descriptor_types';
-import { ITermJoinSource } from '../term_join_source';
-import { BucketProperties, PropertiesMap } from '../../../../common/elasticsearch_util';
-import { IField } from '../../fields/field';
+} from '../../../../../common/descriptor_types';
+import { ITermJoinSource } from '../types';
+import { BucketProperties, PropertiesMap } from '../../../../../common/elasticsearch_util';
+import { IField } from '../../../fields/field';
import {
AbstractVectorSource,
BoundsRequestMeta,
GeoJsonWithMeta,
IVectorSource,
SourceStatus,
-} from '../vector_source';
-import { DataRequest } from '../../util/data_request';
-import { InlineField } from '../../fields/inline_field';
-import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_property';
+} from '../../vector_source';
+import { DataRequest } from '../../../util/data_request';
+import { InlineField } from '../../../fields/inline_field';
+import { ITooltipProperty, TooltipProperty } from '../../../tooltips/tooltip_property';
export class TableSource extends AbstractVectorSource implements ITermJoinSource, IVectorSource {
static type = SOURCE_TYPES.TABLE_SOURCE;
diff --git a/x-pack/plugins/maps/public/classes/sources/term_join_source/term_join_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/types.ts
similarity index 87%
rename from x-pack/plugins/maps/public/classes/sources/term_join_source/term_join_source.ts
rename to x-pack/plugins/maps/public/classes/sources/join_sources/types.ts
index 30e834fdf11f5..05ec53cc14e6a 100644
--- a/x-pack/plugins/maps/public/classes/sources/term_join_source/term_join_source.ts
+++ b/x-pack/plugins/maps/public/classes/sources/join_sources/types.ts
@@ -15,9 +15,8 @@ import { PropertiesMap } from '../../../../common/elasticsearch_util';
import { ITooltipProperty } from '../../tooltips/tooltip_property';
import { ISource } from '../source';
-export interface ITermJoinSource extends ISource {
+export interface IJoinSource extends ISource {
hasCompleteConfig(): boolean;
- getTermField(): IField;
getWhereQuery(): Query | undefined;
getPropertiesMap(
requestMeta: VectorSourceRequestMeta,
@@ -41,3 +40,11 @@ export interface ITermJoinSource extends ISource {
): Promise;
getFieldByName(fieldName: string): IField | null;
}
+
+export interface ITermJoinSource extends IJoinSource {
+ getTermField(): IField;
+}
+
+export function isTermJoinSource(joinSource: IJoinSource) {
+ return 'getTermField' in (joinSource as ITermJoinSource);
+}
diff --git a/x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/index.ts b/x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/index.ts
similarity index 77%
rename from x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/index.ts
rename to x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/index.ts
index 4e48d96b032fe..d28cdbbf58d08 100644
--- a/x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/index.ts
+++ b/x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/index.ts
@@ -5,4 +5,4 @@
* 2.0.
*/
-export { JoinTooltipProperty } from './join_tooltip_property';
+export { TermJoinTooltipProperty } from './term_join_tooltip_property';
diff --git a/x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/join_key_label.tsx b/x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/term_join_key_label.tsx
similarity index 84%
rename from x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/join_key_label.tsx
rename to x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/term_join_key_label.tsx
index 624b7515c04c6..822a966814138 100644
--- a/x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/join_key_label.tsx
+++ b/x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/term_join_key_label.tsx
@@ -16,18 +16,18 @@ import React, { Component } from 'react';
import { asyncMap } from '@kbn/std';
import { i18n } from '@kbn/i18n';
import { EuiIcon, EuiToolTip } from '@elastic/eui';
-import { InnerJoin } from '../../joins/inner_join';
+import type { ITermJoinSource } from '../../sources/join_sources';
interface Props {
leftFieldName: string;
- innerJoins: InnerJoin[];
+ termJoins: ITermJoinSource[];
}
interface State {
rightSourceLabels: string[];
}
-export class JoinKeyLabel extends Component {
+export class TermJoinKeyLabel extends Component {
private _isMounted = false;
state: State = { rightSourceLabels: [] };
@@ -42,9 +42,8 @@ export class JoinKeyLabel extends Component {
}
async _loadRightSourceLabels() {
- const rightSourceLabels = await asyncMap(this.props.innerJoins, async (innerJoin) => {
- const rightSource = innerJoin.getRightJoinSource();
- const termField = rightSource.getTermField();
+ const rightSourceLabels = await asyncMap(this.props.termJoins, async (termJoin) => {
+ const termField = termJoin.getTermField();
return `'${await termField.getLabel()}'`;
});
diff --git a/x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/join_tooltip_property.tsx b/x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/term_join_tooltip_property.tsx
similarity index 74%
rename from x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/join_tooltip_property.tsx
rename to x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/term_join_tooltip_property.tsx
index c6ca5e9b3d5f9..efc15e5a012a2 100644
--- a/x-pack/plugins/maps/public/classes/tooltips/join_tooltip_property/join_tooltip_property.tsx
+++ b/x-pack/plugins/maps/public/classes/tooltips/term_join_tooltip_property/term_join_tooltip_property.tsx
@@ -8,16 +8,16 @@
import React, { ReactNode } from 'react';
import { Filter } from '@kbn/es-query';
import { ITooltipProperty } from '../tooltip_property';
-import { InnerJoin } from '../../joins/inner_join';
-import { JoinKeyLabel } from './join_key_label';
+import { TermJoinKeyLabel } from './term_join_key_label';
+import type { ITermJoinSource } from '../../sources/join_sources';
-export class JoinTooltipProperty implements ITooltipProperty {
+export class TermJoinTooltipProperty implements ITooltipProperty {
private readonly _tooltipProperty: ITooltipProperty;
- private readonly _innerJoins: InnerJoin[];
+ private readonly _termJoins: ITermJoinSource[];
- constructor(tooltipProperty: ITooltipProperty, innerJoins: InnerJoin[]) {
+ constructor(tooltipProperty: ITooltipProperty, termJoins: ITermJoinSource[]) {
this._tooltipProperty = tooltipProperty;
- this._innerJoins = innerJoins;
+ this._termJoins = termJoins;
}
isFilterable(): boolean {
@@ -30,9 +30,9 @@ export class JoinTooltipProperty implements ITooltipProperty {
getPropertyName(): ReactNode {
return (
-
);
}
@@ -50,9 +50,8 @@ export class JoinTooltipProperty implements ITooltipProperty {
// only create filters for right sources.
// do not create filters for left source.
- for (let i = 0; i < this._innerJoins.length; i++) {
- const rightSource = this._innerJoins[i].getRightJoinSource();
- const termField = rightSource.getTermField();
+ for (let i = 0; i < this._termJoins.length; i++) {
+ const termField = this._termJoins[i].getTermField();
try {
const esTooltipProperty = await termField.createTooltipProperty(
this._tooltipProperty.getRawValue()
diff --git a/x-pack/plugins/ml/server/lib/ml_client/types.ts b/x-pack/plugins/ml/server/lib/ml_client/types.ts
index bba5e9b49a0ac..88d1475b23ff7 100644
--- a/x-pack/plugins/ml/server/lib/ml_client/types.ts
+++ b/x-pack/plugins/ml/server/lib/ml_client/types.ts
@@ -13,12 +13,15 @@ export interface UpdateTrainedModelDeploymentRequest {
model_id: string;
number_of_allocations: number;
}
+export interface UpdateTrainedModelDeploymentResponse {
+ acknowledge: boolean;
+}
export interface MlClient extends OrigMlClient {
anomalySearch: ReturnType['anomalySearch'];
updateTrainedModelDeployment: (
payload: UpdateTrainedModelDeploymentRequest
- ) => Promise<{ acknowledge: boolean }>;
+ ) => Promise;
}
export type MlClientParams =
diff --git a/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts b/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts
index 808b1a2f0d4a4..ca2b08702ce72 100644
--- a/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts
+++ b/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts
@@ -7,7 +7,10 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server';
-import { UpdateTrainedModelDeploymentRequest } from '../../lib/ml_client/types';
+import type {
+ UpdateTrainedModelDeploymentRequest,
+ UpdateTrainedModelDeploymentResponse,
+} from '../../lib/ml_client/types';
import type { GetGuards } from '../shared_services';
export interface TrainedModelsProvider {
@@ -21,6 +24,24 @@ export interface TrainedModelsProvider {
getTrainedModelsStats(
params: estypes.MlGetTrainedModelsStatsRequest
): Promise;
+ startTrainedModelDeployment(
+ params: estypes.MlStartTrainedModelDeploymentRequest
+ ): Promise;
+ stopTrainedModelDeployment(
+ params: estypes.MlStopTrainedModelDeploymentRequest
+ ): Promise;
+ inferTrainedModel(
+ params: estypes.MlInferTrainedModelRequest
+ ): Promise;
+ deleteTrainedModel(
+ params: estypes.MlDeleteTrainedModelRequest
+ ): Promise;
+ updateTrainedModelDeployment(
+ params: UpdateTrainedModelDeploymentRequest
+ ): Promise;
+ putTrainedModel(
+ params: estypes.MlPutTrainedModelRequest
+ ): Promise;
};
}
@@ -80,11 +101,19 @@ export function getTrainedModelsProvider(getGuards: GetGuards): TrainedModelsPro
async updateTrainedModelDeployment(params: UpdateTrainedModelDeploymentRequest) {
return await guards
.isFullLicense()
- .hasMlCapabilities(['canStartStopTrainedModels'])
+ .hasMlCapabilities(['canCreateTrainedModels'])
.ok(async ({ mlClient }) => {
return mlClient.updateTrainedModelDeployment(params);
});
},
+ async putTrainedModel(params: estypes.MlPutTrainedModelRequest) {
+ return await guards
+ .isFullLicense()
+ .hasMlCapabilities(['canCreateTrainedModels'])
+ .ok(async ({ mlClient }) => {
+ return mlClient.putTrainedModel(params);
+ });
+ },
};
},
};
diff --git a/x-pack/plugins/observability/common/index.ts b/x-pack/plugins/observability/common/index.ts
index 7ff22e2c50264..628b33ef0a11f 100644
--- a/x-pack/plugins/observability/common/index.ts
+++ b/x-pack/plugins/observability/common/index.ts
@@ -64,6 +64,7 @@ export const syntheticsMonitorDetailLocatorID = 'SYNTHETICS_MONITOR_DETAIL_LOCAT
export const syntheticsEditMonitorLocatorID = 'SYNTHETICS_EDIT_MONITOR_LOCATOR';
export const syntheticsSettingsLocatorID = 'SYNTHETICS_SETTINGS';
export const ruleDetailsLocatorID = 'RULE_DETAILS_LOCATOR';
+export const rulesLocatorID = 'RULES_LOCATOR';
export {
NETWORK_TIMINGS_FIELDS,
diff --git a/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx b/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx
index f72e4b008f390..dbd45bf74dee4 100644
--- a/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx
+++ b/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx
@@ -5,16 +5,21 @@
* 2.0.
*/
+import React from 'react';
import { EuiButton } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import React from 'react';
const SLO_FEEDBACK_LINK = 'https://ela.st/slo-feedback';
-export function FeedbackButton() {
+interface Props {
+ disabled?: boolean;
+}
+
+export function FeedbackButton({ disabled }: Props) {
return (
{
+ const locator = new RulesLocatorDefinition();
+
+ it('should return correct url when empty params are provided', async () => {
+ const location = await locator.getLocation({});
+ expect(location.app).toEqual('observability');
+ expect(location.path).toEqual(
+ `${RULES_PATH}?_a=(lastResponse:!(),params:(),search:'',status:!(),type:!())`
+ );
+ });
+
+ it('should return correct url when lastResponse is provided', async () => {
+ const location = await locator.getLocation({ lastResponse: ['foo'] });
+ expect(location.path).toEqual(
+ `${RULES_PATH}?_a=(lastResponse:!(foo),params:(),search:'',status:!(),type:!())`
+ );
+ });
+
+ it('should return correct url when params is provided', async () => {
+ const location = await locator.getLocation({ params: { sloId: 'foo' } });
+ expect(location.path).toEqual(
+ `${RULES_PATH}?_a=(lastResponse:!(),params:(sloId:foo),search:'',status:!(),type:!())`
+ );
+ });
+
+ it('should return correct url when search is provided', async () => {
+ const location = await locator.getLocation({ search: 'foo' });
+ expect(location.path).toEqual(
+ `${RULES_PATH}?_a=(lastResponse:!(),params:(),search:foo,status:!(),type:!())`
+ );
+ });
+
+ it('should return correct url when status is provided', async () => {
+ const location = await locator.getLocation({ status: ['enabled'] });
+ expect(location.path).toEqual(
+ `${RULES_PATH}?_a=(lastResponse:!(),params:(),search:'',status:!(enabled),type:!())`
+ );
+ });
+
+ it('should return correct url when type is provided', async () => {
+ const location = await locator.getLocation({ type: ['foo'] });
+ expect(location.path).toEqual(
+ `${RULES_PATH}?_a=(lastResponse:!(),params:(),search:'',status:!(),type:!(foo))`
+ );
+ });
+});
diff --git a/x-pack/plugins/observability/public/locators/rules.ts b/x-pack/plugins/observability/public/locators/rules.ts
new file mode 100644
index 0000000000000..533f4ccc98fd1
--- /dev/null
+++ b/x-pack/plugins/observability/public/locators/rules.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; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public';
+import type { SerializableRecord } from '@kbn/utility-types';
+import type { LocatorDefinition } from '@kbn/share-plugin/public';
+import type { RuleStatus } from '@kbn/triggers-actions-ui-plugin/public';
+import { rulesLocatorID } from '../../common';
+
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+export type RulesParams = {
+ lastResponse?: string[];
+ params?: Record;
+ search?: string;
+ status?: RuleStatus[];
+ type?: string[];
+};
+
+export interface RulesLocatorParams extends RulesParams, SerializableRecord {}
+
+export const RULES_PATH = '/alerts/rules';
+
+export class RulesLocatorDefinition implements LocatorDefinition {
+ public readonly id = rulesLocatorID;
+
+ public readonly getLocation = async ({
+ lastResponse = [],
+ params = {},
+ search = '',
+ status = [],
+ type = [],
+ }: RulesLocatorParams) => {
+ return {
+ app: 'observability',
+ path: setStateToKbnUrl(
+ '_a',
+ {
+ lastResponse,
+ params,
+ search,
+ status,
+ type,
+ },
+ { useHash: false, storeInHashQuery: false },
+ RULES_PATH
+ ),
+ state: {},
+ };
+ };
+}
diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx
index 99ce1ba03f9b6..848b35b8bb293 100644
--- a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx
@@ -5,19 +5,26 @@
* 2.0.
*/
-import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
import React, { useState } from 'react';
+import { useIsMutating } from '@tanstack/react-query';
import { i18n } from '@kbn/i18n';
+import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
import { SLOWithSummaryResponse } from '@kbn/slo-schema';
+import { useCapabilities } from '../../../hooks/slo/use_capabilities';
+import { useKibana } from '../../../utils/kibana_react';
import { isApmIndicatorType } from '../../../utils/slo/indicator';
import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url';
import { SLO_BURN_RATE_RULE_ID } from '../../../../common/constants';
-import { sloFeatureId } from '../../../../common';
+import { rulesLocatorID, sloFeatureId } from '../../../../common';
import { paths } from '../../../config/paths';
-import { useKibana } from '../../../utils/kibana_react';
-import { ObservabilityAppServices } from '../../../application/types';
-import { useCapabilities } from '../../../hooks/slo/use_capabilities';
+import { useCloneSlo } from '../../../hooks/slo/use_clone_slo';
+import {
+ transformSloResponseToCreateSloInput,
+ transformValuesToCreateSLOInput,
+} from '../../slo_edit/helpers/process_slo_form_values';
+import { SloDeleteConfirmationModal } from '../../slos/components/slo_delete_confirmation_modal';
+import type { RulesParams } from '../../../locators/rules';
export interface Props {
slo: SLOWithSummaryResponse | undefined;
@@ -28,11 +35,20 @@ export function HeaderControl({ isLoading, slo }: Props) {
const {
application: { navigateToUrl },
http: { basePath },
+ notifications: { toasts },
+ share: {
+ url: { locators },
+ },
triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout },
- } = useKibana().services;
+ } = useKibana().services;
const { hasWriteCapabilities } = useCapabilities();
+
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [isRuleFlyoutVisible, setRuleFlyoutVisibility] = useState(false);
+ const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false);
+
+ const { mutateAsync: cloneSlo } = useCloneSlo();
+ const isDeleting = Boolean(useIsMutating(['deleteSlo', slo?.id]));
const handleActionsClick = () => setIsPopoverOpen((value) => !value);
const closePopover = () => setIsPopoverOpen(false);
@@ -52,12 +68,19 @@ export function HeaderControl({ isLoading, slo }: Props) {
setRuleFlyoutVisibility(true);
};
- const handleNavigateToRules = () => {
- navigateToUrl(
- basePath.prepend(
- `${paths.observability.rules}?_a=(lastResponse:!(),search:%27%27,params:(sloId:%27${slo?.id}%27),status:!(),type:!())`
- )
- );
+ const handleNavigateToRules = async () => {
+ const locator = locators.get(rulesLocatorID);
+
+ if (slo?.id) {
+ locator?.navigate(
+ {
+ params: { sloId: slo.id },
+ },
+ {
+ replace: true,
+ }
+ );
+ }
};
const handleNavigateToApm = () => {
@@ -85,6 +108,40 @@ export function HeaderControl({ isLoading, slo }: Props) {
}
};
+ const handleClone = async () => {
+ if (slo) {
+ setIsPopoverOpen(false);
+
+ const newSlo = transformValuesToCreateSLOInput(
+ transformSloResponseToCreateSloInput({ ...slo, name: `[Copy] ${slo.name}` })!
+ );
+
+ await cloneSlo({ slo: newSlo, idToCopyFrom: slo.id });
+
+ toasts.addSuccess(
+ i18n.translate('xpack.observability.slo.sloDetails.headerControl.cloneSuccess', {
+ defaultMessage: 'Successfully created {name}',
+ values: { name: newSlo.name },
+ })
+ );
+
+ navigateToUrl(basePath.prepend(paths.observability.slos));
+ }
+ };
+
+ const handleDelete = () => {
+ setDeleteConfirmationModalOpen(true);
+ setIsPopoverOpen(false);
+ };
+
+ const handleDeleteCancel = () => {
+ setDeleteConfirmationModalOpen(false);
+ };
+
+ const handleDeleteSuccess = () => {
+ navigateToUrl(basePath.prepend(paths.observability.slos));
+ };
+
return (
<>
{i18n.translate('xpack.observability.slo.sloDetails.headerControl.actions', {
defaultMessage: 'Actions',
@@ -108,11 +165,12 @@ export function HeaderControl({ isLoading, slo }: Props) {
closePopover={closePopover}
>
@@ -123,6 +181,7 @@ export function HeaderControl({ isLoading, slo }: Props) {
@@ -136,6 +195,7 @@ export function HeaderControl({ isLoading, slo }: Props) {
@@ -143,24 +203,50 @@ export function HeaderControl({ isLoading, slo }: Props) {
defaultMessage: 'Manage rules',
})}
,
- ].concat(
- !!slo && isApmIndicatorType(slo.indicator.type)
- ? [
-
- {i18n.translate(
- 'xpack.observability.slos.sloDetails.headerControl.exploreInApm',
- {
- defaultMessage: 'Explore in APM',
- }
- )}
- ,
- ]
- : []
- )}
+ ]
+ .concat(
+ !!slo && isApmIndicatorType(slo.indicator.type) ? (
+
+ {i18n.translate(
+ 'xpack.observability.slos.sloDetails.headerControl.exploreInApm',
+ {
+ defaultMessage: 'Service details',
+ }
+ )}
+
+ ) : (
+ []
+ )
+ )
+ .concat(
+
+ {i18n.translate('xpack.observability.slo.slo.item.actions.clone', {
+ defaultMessage: 'Clone',
+ })}
+ ,
+
+ {i18n.translate('xpack.observability.slo.slo.item.actions.delete', {
+ defaultMessage: 'Delete',
+ })}
+
+ )}
/>
@@ -173,6 +259,14 @@ export function HeaderControl({ isLoading, slo }: Props) {
initialValues={{ name: `${slo.name} burn rate`, params: { sloId: slo.id } }}
/>
) : null}
+
+ {slo && isDeleteConfirmationModalOpen ? (
+
+ ) : null}
>
);
}
diff --git a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx
index 4028b80203591..1dc86a2901a44 100644
--- a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx
@@ -49,6 +49,7 @@ const useCapabilitiesMock = useCapabilities as jest.Mock;
const mockNavigate = jest.fn();
const mockBasePathPrepend = jest.fn();
+const mockLocator = jest.fn();
const mockKibana = () => {
useKibanaMock.mockReturnValue({
@@ -60,6 +61,19 @@ const mockKibana = () => {
prepend: mockBasePathPrepend,
},
},
+ notifications: {
+ toasts: {
+ addSuccess: jest.fn(),
+ addError: jest.fn(),
+ },
+ },
+ share: {
+ url: {
+ locators: {
+ get: mockLocator,
+ },
+ },
+ },
triggersActionsUi: {
getAddRuleFlyout: jest.fn(() => (
mocked component
@@ -182,6 +196,49 @@ describe('SLO Details Page', () => {
expect(screen.queryByTestId('sloDetailsHeaderControlPopoverCreateRule')).toBeTruthy();
});
+ it("renders a 'Manage rules' button under actions menu", async () => {
+ const slo = buildSlo();
+ useParamsMock.mockReturnValue(slo.id);
+ useFetchSloDetailsMock.mockReturnValue({ isLoading: false, slo });
+ useLicenseMock.mockReturnValue({ hasAtLeast: () => true });
+
+ render();
+
+ fireEvent.click(screen.getByTestId('o11yHeaderControlActionsButton'));
+ expect(screen.queryByTestId('sloDetailsHeaderControlPopoverManageRules')).toBeTruthy();
+ });
+
+ it("renders a 'Clone' button under actions menu", async () => {
+ const slo = buildSlo();
+ useParamsMock.mockReturnValue(slo.id);
+ useFetchSloDetailsMock.mockReturnValue({ isLoading: false, slo });
+ useLicenseMock.mockReturnValue({ hasAtLeast: () => true });
+
+ render();
+
+ fireEvent.click(screen.getByTestId('o11yHeaderControlActionsButton'));
+ expect(screen.queryByTestId('sloDetailsHeaderControlPopoverClone')).toBeTruthy();
+ });
+
+ it("renders a 'Delete' button under actions menu", async () => {
+ const slo = buildSlo();
+ useParamsMock.mockReturnValue(slo.id);
+ useFetchSloDetailsMock.mockReturnValue({ isLoading: false, slo });
+ useLicenseMock.mockReturnValue({ hasAtLeast: () => true });
+
+ render();
+
+ fireEvent.click(screen.getByTestId('o11yHeaderControlActionsButton'));
+ expect(screen.queryByTestId('sloDetailsHeaderControlPopoverDelete')).toBeTruthy();
+
+ const manageRulesButton = screen.queryByTestId('sloDetailsHeaderControlPopoverManageRules');
+ expect(manageRulesButton).toBeTruthy();
+
+ fireEvent.click(manageRulesButton!);
+
+ expect(mockLocator).toBeCalled();
+ });
+
it('renders the Overview tab by default', async () => {
const slo = buildSlo();
useParamsMock.mockReturnValue(slo.id);
diff --git a/x-pack/plugins/observability/public/pages/slo_details/slo_details.tsx b/x-pack/plugins/observability/public/pages/slo_details/slo_details.tsx
index 48401ca29f94e..29a7f573e3c14 100644
--- a/x-pack/plugins/observability/public/pages/slo_details/slo_details.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_details/slo_details.tsx
@@ -7,6 +7,7 @@
import React, { useState } from 'react';
import { useParams } from 'react-router-dom';
+import { useIsMutating } from '@tanstack/react-query';
import { EuiBreadcrumbProps } from '@elastic/eui/src/components/breadcrumbs/breadcrumb';
import { EuiLoadingSpinner } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@@ -44,6 +45,8 @@ export function SloDetailsPage() {
const { isLoading, slo } = useFetchSloDetails({ sloId, shouldRefetch: isAutoRefreshing });
+ const isCloningOrDeleting = Boolean(useIsMutating());
+
useBreadcrumbs(getBreadcrumbs(basePath, slo));
const isSloNotFound = !isLoading && slo === undefined;
@@ -55,6 +58,8 @@ export function SloDetailsPage() {
navigateToUrl(basePath.prepend(paths.observability.slos));
}
+ const isPerformingAction = isLoading || isCloningOrDeleting;
+
const handleToggleAutoRefresh = () => {
setIsAutoRefreshing(!isAutoRefreshing);
};
@@ -62,15 +67,15 @@ export function SloDetailsPage() {
return (
,
+ pageTitle: ,
rightSideItems: [
- ,
+ ,
,
- ,
+ ,
],
bottomBorder: false,
}}
diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx
index 87f005e2fa5c0..ad73af3d73bfa 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx
@@ -63,7 +63,7 @@ export function SloIndicatorTypeBadge({ slo }: Props) {
@@ -73,7 +73,7 @@ export function SloIndicatorTypeBadge({ slo }: Props) {
onClickAriaLabel={i18n.translate(
'xpack.observability.slo.indicatorTypeBadge.exploreInApm',
{
- defaultMessage: 'Explore {service} in APM',
+ defaultMessage: 'View {service} details',
values: { service: slo.indicator.params.service },
}
)}
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_delete_confirmation_modal.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_delete_confirmation_modal.tsx
index 4a292bef8c14b..b1b2d341a9bd8 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_delete_confirmation_modal.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_delete_confirmation_modal.tsx
@@ -15,11 +15,13 @@ import { useDeleteSlo } from '../../../hooks/slo/use_delete_slo';
export interface SloDeleteConfirmationModalProps {
slo: SLOWithSummaryResponse;
onCancel: () => void;
+ onSuccess?: () => void;
}
export function SloDeleteConfirmationModal({
slo: { id, name },
onCancel,
+ onSuccess,
}: SloDeleteConfirmationModalProps) {
const {
notifications: { toasts },
@@ -31,6 +33,7 @@ export function SloDeleteConfirmationModal({
if (isSuccess) {
toasts.addSuccess(getDeleteSuccesfulMessage(name));
+ onSuccess?.();
}
if (isError) {
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx
index 049481486eb9e..3fe0f5d31f543 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx
@@ -34,10 +34,11 @@ import {
transformValuesToCreateSLOInput,
} from '../../slo_edit/helpers/process_slo_form_values';
import { SLO_BURN_RATE_RULE_ID } from '../../../../common/constants';
-import { sloFeatureId } from '../../../../common';
+import { rulesLocatorID, sloFeatureId } from '../../../../common';
import { paths } from '../../../config/paths';
import type { ActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts';
import type { SloRule } from '../../../hooks/slo/use_fetch_rules_for_slo';
+import type { RulesParams } from '../../../locators/rules';
export interface SloListItemProps {
slo: SLOWithSummaryResponse;
@@ -57,6 +58,9 @@ export function SloListItem({
const {
application: { navigateToUrl },
http: { basePath },
+ share: {
+ url: { locators },
+ },
triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout },
} = useKibana().services;
const { hasWriteCapabilities } = useCapabilities();
@@ -92,11 +96,16 @@ export function SloListItem({
queryClient.invalidateQueries(['fetchRulesForSlo']);
};
- const handleNavigateToRules = () => {
- navigateToUrl(
- basePath.prepend(
- `${paths.observability.rules}?_a=(lastResponse:!(),search:%27%27,params:(sloId:%27${slo?.id}%27),status:!(),type:!())`
- )
+ const handleNavigateToRules = async () => {
+ const locator = locators.get(rulesLocatorID);
+
+ locator?.navigate(
+ {
+ params: { sloId: slo.id },
+ },
+ {
+ replace: true,
+ }
);
};
@@ -175,12 +184,12 @@ export function SloListItem({
onClick={handleClickActions}
/>
}
- panelPaddingSize="none"
+ panelPaddingSize="m"
closePopover={handleClickActions}
isOpen={isActionsPopoverOpen}
>
{i18n.translate('xpack.observability.slo.slo.item.actions.createRule', {
- defaultMessage: 'Create new Alert rule',
+ defaultMessage: 'Create new alert rule',
})}
,
Add rule flyout
);
const mockKibana = () => {
@@ -78,6 +79,13 @@ const mockKibana = () => {
addError: mockAddError,
},
},
+ share: {
+ url: {
+ locators: {
+ get: mockLocator,
+ },
+ },
+ },
triggersActionsUi: { getAddRuleFlyout: mockGetAddRuleFlyout },
uiSettings: {
get: (settings: string) => {
@@ -226,6 +234,31 @@ describe('SLOs Page', () => {
expect(mockGetAddRuleFlyout).toBeCalled();
});
+ it('allows managing rules for an SLO', async () => {
+ useFetchSloListMock.mockReturnValue({ isLoading: false, sloList });
+
+ useFetchHistoricalSummaryMock.mockReturnValue({
+ isLoading: false,
+ sloHistoricalSummaryResponse: historicalSummaryData,
+ });
+
+ await act(async () => {
+ render();
+ });
+
+ screen.getAllByLabelText('Actions').at(0)?.click();
+
+ await waitForEuiPopoverOpen();
+
+ const button = screen.getByTestId('sloActionsManageRules');
+
+ expect(button).toBeTruthy();
+
+ button.click();
+
+ expect(mockLocator).toBeCalled();
+ });
+
it('allows deleting an SLO', async () => {
useFetchSloListMock.mockReturnValue({ isLoading: false, sloList });
diff --git a/x-pack/plugins/observability/public/pages/slos/slos.tsx b/x-pack/plugins/observability/public/pages/slos/slos.tsx
index b81998d8452de..f9cf30cb7b344 100644
--- a/x-pack/plugins/observability/public/pages/slos/slos.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/slos.tsx
@@ -18,10 +18,10 @@ import { useFetchSloList } from '../../hooks/slo/use_fetch_slo_list';
import { SloList } from './components/slo_list';
import { SloListWelcomePrompt } from './components/slo_list_welcome_prompt';
import { AutoRefreshButton } from './components/auto_refresh_button';
-import { paths } from '../../config/paths';
-import type { ObservabilityAppServices } from '../../application/types';
import { HeaderTitle } from './components/header_title';
import { FeedbackButton } from '../../components/slo/feedback_button/feedback_button';
+import { paths } from '../../config/paths';
+import type { ObservabilityAppServices } from '../../application/types';
export function SlosPage() {
const {
diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts
index 190c646bebbcc..3ea0c8b797c40 100644
--- a/x-pack/plugins/observability/public/plugin.ts
+++ b/x-pack/plugins/observability/public/plugin.ts
@@ -50,6 +50,7 @@ import { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import { ExploratoryViewPublicStart } from '@kbn/exploratory-view-plugin/public';
import { RuleDetailsLocatorDefinition } from './locators/rule_details';
+import { RulesLocatorDefinition } from './locators/rules';
import { observabilityAppId, observabilityFeatureId, casesPath } from '../common';
import { registerDataHandler } from './data_handler';
import {
@@ -190,6 +191,9 @@ export class Plugin
this.observabilityRuleTypeRegistry = createObservabilityRuleTypeRegistry(
pluginsSetup.triggersActionsUi.ruleTypeRegistry
);
+
+ const locator = pluginsSetup.share.url.locators.create(new RulesLocatorDefinition());
+
pluginsSetup.share.url.locators.create(new RuleDetailsLocatorDefinition());
const mount = async (params: AppMountParameters) => {
@@ -310,6 +314,7 @@ export class Plugin
dashboard: { register: registerDataHandler },
observabilityRuleTypeRegistry: this.observabilityRuleTypeRegistry,
useRulesLink: createUseRulesLink(),
+ rulesLocator: locator,
};
}
diff --git a/x-pack/plugins/observability/server/index.ts b/x-pack/plugins/observability/server/index.ts
index fea9b0ab14195..33ef9d2c62d4d 100644
--- a/x-pack/plugins/observability/server/index.ts
+++ b/x-pack/plugins/observability/server/index.ts
@@ -41,6 +41,7 @@ const configSchema = schema.object({
}),
}),
}),
+ enabled: schema.boolean({ defaultValue: true }),
});
export const config: PluginConfigDescriptor = {
diff --git a/x-pack/plugins/remote_clusters/server/config.ts b/x-pack/plugins/remote_clusters/server/config.ts
index 32db006e8171a..4f6c56191cd89 100644
--- a/x-pack/plugins/remote_clusters/server/config.ts
+++ b/x-pack/plugins/remote_clusters/server/config.ts
@@ -22,6 +22,11 @@ const schemaLatest = schema.object(
ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
+ /**
+ * Disables the plugin.
+ * Added back in 8.8.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
},
{ defaultValue: undefined }
);
diff --git a/x-pack/plugins/rollup/server/config.ts b/x-pack/plugins/rollup/server/config.ts
index 235202a23db24..953cd4b283f97 100644
--- a/x-pack/plugins/rollup/server/config.ts
+++ b/x-pack/plugins/rollup/server/config.ts
@@ -22,6 +22,11 @@ const schemaLatest = schema.object(
ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
+ /**
+ * Disables the plugin.
+ * Added back in 8.8.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
},
{ defaultValue: undefined }
);
diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts
index cb4d9d734bd02..a69e3b657aeb2 100644
--- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts
+++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts
@@ -195,7 +195,7 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
start: Date.parse(alert[TIMESTAMP]),
end: Date.parse(alert[TIMESTAMP]),
}),
- alerts: [alert],
+ alerts: [formatAlert?.(alert) ?? alert],
})
);
@@ -387,7 +387,7 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
start: Date.parse(alert[TIMESTAMP]),
end: Date.parse(alert[TIMESTAMP]),
}),
- alerts: [alert],
+ alerts: [formatAlert?.(alert) ?? alert],
})
);
diff --git a/x-pack/plugins/security_solution/common/utils/expand_dotted.test.ts b/x-pack/plugins/security_solution/common/utils/expand_dotted.test.ts
index 018220e400937..d3f227274e7f1 100644
--- a/x-pack/plugins/security_solution/common/utils/expand_dotted.test.ts
+++ b/x-pack/plugins/security_solution/common/utils/expand_dotted.test.ts
@@ -70,6 +70,18 @@ describe('Expand Dotted', () => {
});
});
+ it('overwrites earlier fields when later fields conflict', () => {
+ const simpleDottedObj = {
+ 'kibana.test.1': 'the spice must flow',
+ 'kibana.test': 2,
+ };
+ expect(expandDottedObject(simpleDottedObj)).toEqual({
+ kibana: {
+ test: 2,
+ },
+ });
+ });
+
it('expands non dotted field without changing it other than reference', () => {
const simpleDottedObj = {
test: { value: '123' },
diff --git a/x-pack/plugins/security_solution/common/utils/expand_dotted.ts b/x-pack/plugins/security_solution/common/utils/expand_dotted.ts
index f90f589486ff5..4aa56b021244b 100644
--- a/x-pack/plugins/security_solution/common/utils/expand_dotted.ts
+++ b/x-pack/plugins/security_solution/common/utils/expand_dotted.ts
@@ -5,16 +5,7 @@
* 2.0.
*/
-import { merge } from '@kbn/std';
-
-const expandDottedField = (dottedFieldName: string, val: unknown): object => {
- const parts = dottedFieldName.split('.');
- if (parts.length === 1) {
- return { [parts[0]]: val };
- } else {
- return { [parts[0]]: expandDottedField(parts.slice(1).join('.'), val) };
- }
-};
+import { setWith } from 'lodash';
/*
* Expands an object with "dotted" fields to a nested object with unflattened fields.
@@ -48,8 +39,9 @@ export const expandDottedObject = (dottedObj: object) => {
if (Array.isArray(dottedObj)) {
return dottedObj;
}
- return Object.entries(dottedObj).reduce(
- (acc, [key, val]) => merge(acc, expandDottedField(key, val)),
- {}
- );
+ const returnObj = {};
+ Object.entries(dottedObj).forEach(([key, value]) => {
+ setWith(returnObj, key, value, Object);
+ });
+ return returnObj;
};
diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts
index c1faa6f401a1d..6fcaa94629643 100644
--- a/x-pack/plugins/security_solution/server/config.mock.ts
+++ b/x-pack/plugins/security_solution/server/config.mock.ts
@@ -31,6 +31,7 @@ export const createMockConfig = (): ConfigType => {
alertIgnoreFields: [],
experimentalFeatures: parseExperimentalConfigValue(enableExperimental),
+ enabled: true,
};
};
diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts
index 26f1be4f014b3..a0283858590cb 100644
--- a/x-pack/plugins/security_solution/server/config.ts
+++ b/x-pack/plugins/security_solution/server/config.ts
@@ -122,6 +122,7 @@ export const configSchema = schema.object({
* the package is not already installed.
*/
prebuiltRulesPackageVersion: schema.maybe(schema.string()),
+ enabled: schema.boolean({ defaultValue: true }),
});
export type ConfigSchema = TypeOf;
diff --git a/x-pack/plugins/snapshot_restore/server/config.ts b/x-pack/plugins/snapshot_restore/server/config.ts
index d259b6674391a..e2452e5b58e54 100644
--- a/x-pack/plugins/snapshot_restore/server/config.ts
+++ b/x-pack/plugins/snapshot_restore/server/config.ts
@@ -25,6 +25,11 @@ const schemaLatest = schema.object(
slm_ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
+ /**
+ * Disables the plugin.
+ * Added back in 8.8.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
},
{ defaultValue: undefined }
);
diff --git a/x-pack/plugins/synthetics/common/config.ts b/x-pack/plugins/synthetics/common/config.ts
index c9c48e5878391..9da43f8bf9a08 100644
--- a/x-pack/plugins/synthetics/common/config.ts
+++ b/x-pack/plugins/synthetics/common/config.ts
@@ -23,6 +23,7 @@ const serviceConfig = schema.object({
const uptimeConfig = schema.object({
index: schema.maybe(schema.string()),
service: schema.maybe(serviceConfig),
+ enabled: schema.boolean({ defaultValue: true }),
});
export const config: PluginConfigDescriptor = {
diff --git a/x-pack/plugins/synthetics/kibana.jsonc b/x-pack/plugins/synthetics/kibana.jsonc
index a70202e3126a1..1cc3b45f4637d 100644
--- a/x-pack/plugins/synthetics/kibana.jsonc
+++ b/x-pack/plugins/synthetics/kibana.jsonc
@@ -12,6 +12,8 @@
"actions",
"alerting",
"cases",
+ "data",
+ "fleet",
"embeddable",
"discover",
"dataViews",
@@ -44,4 +46,4 @@
"indexLifecycleManagement"
]
}
-}
+}
\ No newline at end of file
diff --git a/x-pack/plugins/synthetics/server/synthetics_service/get_service_locations.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/get_service_locations.test.ts
index 1fed640bcb4e8..58faf6ba14877 100644
--- a/x-pack/plugins/synthetics/server/synthetics_service/get_service_locations.test.ts
+++ b/x-pack/plugins/synthetics/server/synthetics_service/get_service_locations.test.ts
@@ -50,6 +50,7 @@ describe('getServiceLocations', function () {
manifestUrl: 'http://local.dev',
showExperimentalLocations: false,
},
+ enabled: true,
},
// @ts-ignore
logger: {
@@ -101,6 +102,7 @@ describe('getServiceLocations', function () {
manifestUrl: 'http://local.dev',
showExperimentalLocations: false,
},
+ enabled: true,
},
// @ts-ignore
logger: {
@@ -138,6 +140,7 @@ describe('getServiceLocations', function () {
manifestUrl: 'http://local.dev',
showExperimentalLocations: true,
},
+ enabled: true,
},
// @ts-ignore
logger: {
diff --git a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.test.ts
index 35e31add55aa0..86933fc51e4fd 100644
--- a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.test.ts
+++ b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.test.ts
@@ -80,6 +80,7 @@ describe('SyntheticsService', () => {
password: '12345',
manifestUrl: 'http://localhost:8080/api/manifest',
},
+ enabled: true,
},
coreStart: mockCoreStart,
encryptedSavedObjects: mockEncryptedSO(),
@@ -101,7 +102,11 @@ describe('SyntheticsService', () => {
};
});
serverMock.config = {
- service: { devUrl: 'http://localhost', manifestUrl: 'https://test-manifest.com' },
+ service: {
+ devUrl: 'http://localhost',
+ manifestUrl: 'https://test-manifest.com',
+ },
+ enabled: true,
};
if (serverMock.savedObjectsClient) {
serverMock.savedObjectsClient.find = jest.fn().mockResolvedValue({
@@ -165,6 +170,7 @@ describe('SyntheticsService', () => {
username: 'dev',
password: '12345',
},
+ enabled: true,
};
const service = new SyntheticsService(serverMock);
diff --git a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts
index 3e420bf478dec..69fc7ce0ee6dc 100644
--- a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts
+++ b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts
@@ -108,6 +108,10 @@ export class SyntheticsService {
}
public async setupIndexTemplates() {
+ if (process.env.CI && !this.config?.manifestUrl) {
+ // skip installation on CI
+ return;
+ }
if (this.indexTemplateExists) {
// if already installed, don't need to reinstall
return;
diff --git a/x-pack/plugins/upgrade_assistant/server/config.ts b/x-pack/plugins/upgrade_assistant/server/config.ts
index 6202a6680708a..bf872f50b5222 100644
--- a/x-pack/plugins/upgrade_assistant/server/config.ts
+++ b/x-pack/plugins/upgrade_assistant/server/config.ts
@@ -12,6 +12,11 @@ import { PluginConfigDescriptor } from '@kbn/core/server';
// even for minor releases.
// -------------------------------
const configSchema = schema.object({
+ /**
+ * Disables the plugin.
+ */
+ enabled: schema.boolean({ defaultValue: true }),
+
featureSet: schema.object({
/**
* Ml Snapshot should only be enabled for major version upgrades. Currently this
@@ -39,6 +44,9 @@ const configSchema = schema.object({
*/
reindexCorrectiveActions: schema.boolean({ defaultValue: false }),
}),
+ /**
+ * This config allows to hide the UI without disabling the plugin.
+ */
ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
diff --git a/x-pack/plugins/watcher/server/index.ts b/x-pack/plugins/watcher/server/index.ts
index 0aba44ed82838..36453f571f162 100644
--- a/x-pack/plugins/watcher/server/index.ts
+++ b/x-pack/plugins/watcher/server/index.ts
@@ -6,6 +6,14 @@
*/
import { PluginInitializerContext } from '@kbn/core/server';
+import { schema } from '@kbn/config-schema';
+
import { WatcherServerPlugin } from './plugin';
export const plugin = (ctx: PluginInitializerContext) => new WatcherServerPlugin(ctx);
+
+export const config = {
+ schema: schema.object({
+ enabled: schema.boolean({ defaultValue: true }),
+ }),
+};
diff --git a/x-pack/test/api_integration/config.ts b/x-pack/test/api_integration/config.ts
index 5766a9efdf982..e43c76d42adfa 100644
--- a/x-pack/test/api_integration/config.ts
+++ b/x-pack/test/api_integration/config.ts
@@ -30,9 +30,6 @@ export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProvi
'--xpack.ruleRegistry.write.enabled=true',
'--xpack.ruleRegistry.write.enabled=true',
'--xpack.ruleRegistry.write.cache.enabled=false',
- '--xpack.uptime.service.password=test',
- '--xpack.uptime.service.username=localKibanaIntegrationTestsUser',
- '--xpack.uptime.service.devUrl=mockDevUrl',
'--monitoring_collection.opentelemetry.metrics.prometheus.enabled=true',
],
},
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/agent/stream/log.yml.hbs b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/agent/stream/log.yml.hbs
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/agent/stream/log.yml.hbs
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/agent/stream/log.yml.hbs
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/fields/ecs.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/fields/ecs.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/fields/ecs.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/fields/ecs.yml
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/fields/fields.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/fields/fields.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/fields/fields.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/fields/fields.yml
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/manifest.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/manifest.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_logs/manifest.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_logs/manifest.yml
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/agent/stream/cpu.yml.hbs b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/agent/stream/cpu.yml.hbs
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/agent/stream/cpu.yml.hbs
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/agent/stream/cpu.yml.hbs
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/fields/ecs.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/fields/ecs.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/fields/ecs.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/fields/ecs.yml
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/fields/fields.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/fields/fields.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/fields/fields.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/fields/fields.yml
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/manifest.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/manifest.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/data_stream/test_metrics/manifest.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/data_stream/test_metrics/manifest.yml
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/docs/README.md b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/docs/README.md
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/docs/README.md
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/docs/README.md
diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/manifest.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/manifest.yml
similarity index 100%
rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/0.2.0/manifest.yml
rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/dynamic_datastream/1.2.0/manifest.yml
diff --git a/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts b/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts
index baae09f47c530..2aaee38790403 100644
--- a/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts
+++ b/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts
@@ -26,7 +26,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const es = getService('es');
const security = getService('security');
- describe('Ingest Pipelines', function () {
+ // FAILING VERSION BUMP: https://github.com/elastic/kibana/issues/155914
+ describe.skip('Ingest Pipelines', function () {
this.tags('smoke');
before(async () => {
await security.testUser.setRoles(['ingest_pipelines_user']);