diff --git a/examples/controls_example/public/react_controls/control_group/components/control_group.tsx b/examples/controls_example/public/react_controls/control_group/components/control_group.tsx index c8eb00b52ed9d..9608d8b082f40 100644 --- a/examples/controls_example/public/react_controls/control_group/components/control_group.tsx +++ b/examples/controls_example/public/react_controls/control_group/components/control_group.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { BehaviorSubject } from 'rxjs'; import { DndContext, @@ -98,64 +98,84 @@ export function ControlGroup({ }; }, [controlGroupApi]); + const ApplyButtonComponent = useMemo(() => { + return ( + + ); + }, [hasUnappliedSelections, applySelections]); + return ( - - + + {!isInitialized && } - setDraggingId(`${active.id}`)} - onDragEnd={onDragEnd} - onDragCancel={() => setDraggingId(null)} - sensors={sensors} - measuring={{ - droppable: { - strategy: MeasuringStrategy.BeforeDragging, - }, - }} - > - - {controlsInOrder.map(({ id, type }) => ( - controlGroupApi} - onApiAvailable={(controlApi) => { - controlsManager.setControlApi(id, controlApi); - }} - isControlGroupInitialized={isInitialized} - /> - ))} - - - {draggingId ? ( - - ) : null} - - - {!autoApplySelections && ( - - - - + + setDraggingId(`${active.id}`)} + onDragEnd={onDragEnd} + onDragCancel={() => setDraggingId(null)} + sensors={sensors} + measuring={{ + droppable: { + strategy: MeasuringStrategy.BeforeDragging, + }, + }} + > + + + {controlsInOrder.map(({ id, type }) => ( + controlGroupApi} + onApiAvailable={(controlApi) => { + controlsManager.setControlApi(id, controlApi); + }} + isControlGroupInitialized={isInitialized} + /> + ))} + + + + {draggingId ? ( + + ) : null} + + + + {isInitialized && !autoApplySelections && ( + + {hasUnappliedSelections ? ( + ApplyButtonComponent + ) : ( + + {ApplyButtonComponent} + + )} )} diff --git a/examples/controls_example/public/react_controls/timeslider_control/components/index.scss b/examples/controls_example/public/react_controls/timeslider_control/components/index.scss index 9fb6510b1a934..de3677656848a 100644 --- a/examples/controls_example/public/react_controls/timeslider_control/components/index.scss +++ b/examples/controls_example/public/react_controls/timeslider_control/components/index.scss @@ -1,5 +1,8 @@ -.timeSlider-playToggle:enabled { - background-color: $euiColorPrimary !important; +.timeSlider-playToggle { + height: 100%; + &:enabled { + background-color: $euiColorPrimary !important; + } } .timeSlider-prependButton { diff --git a/examples/controls_example/public/react_controls/timeslider_control/components/play_button.tsx b/examples/controls_example/public/react_controls/timeslider_control/components/play_button.tsx index c30bff5c2926d..8fe19bca8a054 100644 --- a/examples/controls_example/public/react_controls/timeslider_control/components/play_button.tsx +++ b/examples/controls_example/public/react_controls/timeslider_control/components/play_button.tsx @@ -41,7 +41,11 @@ export function PlayButton(props: Props) { /> ); return props.disablePlayButton ? ( - + {Button} ) : ( diff --git a/examples/response_stream/common/api/reducer_stream/index.ts b/examples/response_stream/common/api/reducer_stream/index.ts index cc5255761fbd6..13f3c0274f771 100644 --- a/examples/response_stream/common/api/reducer_stream/index.ts +++ b/examples/response_stream/common/api/reducer_stream/index.ts @@ -7,5 +7,3 @@ */ export { reducerStreamReducer } from './reducer'; -export { reducerStreamRequestBodySchema } from './request_body_schema'; -export type { ReducerStreamRequestBodySchema } from './request_body_schema'; diff --git a/examples/response_stream/server/routes/reducer_stream.ts b/examples/response_stream/server/routes/reducer_stream.ts index abdc90f28a23c..9a84d3009b6c3 100644 --- a/examples/response_stream/server/routes/reducer_stream.ts +++ b/examples/response_stream/server/routes/reducer_stream.ts @@ -16,7 +16,7 @@ import { deleteEntityAction, ReducerStreamApiAction, } from '../../common/api/reducer_stream/reducer_actions'; -import { reducerStreamRequestBodySchema } from '../../common/api/reducer_stream'; +import { reducerStreamRequestBodySchema } from './schemas/reducer_stream'; import { RESPONSE_STREAM_API_ENDPOINT } from '../../common/api'; import { entities, getActions } from './shared'; diff --git a/examples/response_stream/server/routes/redux_stream.ts b/examples/response_stream/server/routes/redux_stream.ts index bd694c531907b..700e1ff3d06c4 100644 --- a/examples/response_stream/server/routes/redux_stream.ts +++ b/examples/response_stream/server/routes/redux_stream.ts @@ -16,7 +16,7 @@ import { error, type ReduxStreamApiAction, } from '../../common/api/redux_stream/data_slice'; -import { reducerStreamRequestBodySchema } from '../../common/api/reducer_stream'; +import { reducerStreamRequestBodySchema } from './schemas/reducer_stream'; import { RESPONSE_STREAM_API_ENDPOINT } from '../../common/api'; import { entities, getActions } from './shared'; diff --git a/examples/response_stream/server/routes/schemas/reducer_stream/index.ts b/examples/response_stream/server/routes/schemas/reducer_stream/index.ts new file mode 100644 index 0000000000000..62247bb3f3045 --- /dev/null +++ b/examples/response_stream/server/routes/schemas/reducer_stream/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { reducerStreamRequestBodySchema } from './request_body_schema'; +export type { ReducerStreamRequestBodySchema } from './request_body_schema'; diff --git a/examples/response_stream/common/api/reducer_stream/request_body_schema.ts b/examples/response_stream/server/routes/schemas/reducer_stream/request_body_schema.ts similarity index 100% rename from examples/response_stream/common/api/reducer_stream/request_body_schema.ts rename to examples/response_stream/server/routes/schemas/reducer_stream/request_body_schema.ts diff --git a/examples/response_stream/common/api/simple_string_stream/index.ts b/examples/response_stream/server/routes/schemas/simple_string_stream/index.ts similarity index 100% rename from examples/response_stream/common/api/simple_string_stream/index.ts rename to examples/response_stream/server/routes/schemas/simple_string_stream/index.ts diff --git a/examples/response_stream/common/api/simple_string_stream/request_body_schema.ts b/examples/response_stream/server/routes/schemas/simple_string_stream/request_body_schema.ts similarity index 100% rename from examples/response_stream/common/api/simple_string_stream/request_body_schema.ts rename to examples/response_stream/server/routes/schemas/simple_string_stream/request_body_schema.ts diff --git a/examples/response_stream/server/routes/single_string_stream.ts b/examples/response_stream/server/routes/single_string_stream.ts index d9cb65686b71e..daf0ae682a14e 100644 --- a/examples/response_stream/server/routes/single_string_stream.ts +++ b/examples/response_stream/server/routes/single_string_stream.ts @@ -9,7 +9,7 @@ import type { IRouter, Logger } from '@kbn/core/server'; import { streamFactory } from '@kbn/ml-response-stream/server'; -import { simpleStringStreamRequestBodySchema } from '../../common/api/simple_string_stream'; +import { simpleStringStreamRequestBodySchema } from './schemas/simple_string_stream'; import { RESPONSE_STREAM_API_ENDPOINT } from '../../common/api'; function timeout(ms: number) { diff --git a/packages/kbn-cli-dev-mode/kibana.jsonc b/packages/kbn-cli-dev-mode/kibana.jsonc index 3c55d047b0efc..fcacb342273f5 100644 --- a/packages/kbn-cli-dev-mode/kibana.jsonc +++ b/packages/kbn-cli-dev-mode/kibana.jsonc @@ -1,5 +1,5 @@ { - "type": "shared-common", + "type": "shared-server", "id": "@kbn/cli-dev-mode", "devOnly": true, "owner": "@elastic/kibana-operations" diff --git a/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/namespace_components.ts b/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/namespace_components.ts index 01ef116082fe1..76b144ef0804d 100644 --- a/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/namespace_components.ts +++ b/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/namespace_components.ts @@ -10,6 +10,7 @@ import { extractByJsonPointer } from '../../../utils/extract_by_json_pointer'; import { isPlainObjectType } from '../../../utils/is_plain_object_type'; import { parseRef } from '../../../utils/parse_ref'; import { DocumentNodeProcessor } from './types/document_node_processor'; +import { isLocalRef } from './utils/is_local_ref'; /** * Creates a node processor to prefix possibly conflicting components and security requirements @@ -58,6 +59,23 @@ export function createNamespaceComponentsProcessor(pointer: string): DocumentNod // `components.securitySchemes`. It means items in `security` implicitly reference // `components.securitySchemes` items which should be handled. onNodeLeave(node, context) { + // Handle mappings + if (context.parentKey === 'mapping' && isPlainObjectType(node)) { + for (const key of Object.keys(node)) { + const maybeRef = node[key]; + + if (typeof maybeRef !== 'string' || !isLocalRef(maybeRef)) { + throw new Error( + `Expected mappings to have local references but got "${maybeRef}" in ${JSON.stringify( + node + )}` + ); + } + + node[key] = decorateRefBaseName(maybeRef, namespace); + } + } + if ('security' in node && Array.isArray(node.security)) { for (const securityRequirements of node.security) { prefixObjectKeys(securityRequirements); diff --git a/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/utils/is_local_ref.ts b/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/utils/is_local_ref.ts new file mode 100644 index 0000000000000..8e3caa8e9deb8 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/process_document/document_processors/utils/is_local_ref.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export function isLocalRef(ref: string): boolean { + return ref.startsWith('#/'); +} diff --git a/packages/kbn-openapi-bundler/src/openapi_merger.ts b/packages/kbn-openapi-bundler/src/openapi_merger.ts index 773edb816c472..a7ac3c3492dfe 100644 --- a/packages/kbn-openapi-bundler/src/openapi_merger.ts +++ b/packages/kbn-openapi-bundler/src/openapi_merger.ts @@ -22,9 +22,6 @@ export interface MergerConfig { outputFilePath: string; options?: { mergedSpecInfo?: Partial; - conflictsResolution?: { - prependComponentsWith: 'title'; - }; }; } diff --git a/packages/kbn-openapi-bundler/src/utils/write_documents.ts b/packages/kbn-openapi-bundler/src/utils/write_documents.ts index 40311bc7d61e1..f0834ebb5ca00 100644 --- a/packages/kbn-openapi-bundler/src/utils/write_documents.ts +++ b/packages/kbn-openapi-bundler/src/utils/write_documents.ts @@ -45,5 +45,5 @@ function getVersionedOutputFilePath(outputFilePath: string, version: string): st const filename = basename(outputFilePath); - return outputFilePath.replace(filename, `${version}-${filename}`); + return outputFilePath.replace(filename, `${version}_${filename}`); } diff --git a/packages/kbn-openapi-bundler/tests/merger/merging_specs_with_conflicting_components.test.ts b/packages/kbn-openapi-bundler/tests/merger/merging_specs_with_conflicting_components.test.ts index c77d2a08a644a..edf2b44725acf 100644 --- a/packages/kbn-openapi-bundler/tests/merger/merging_specs_with_conflicting_components.test.ts +++ b/packages/kbn-openapi-bundler/tests/merger/merging_specs_with_conflicting_components.test.ts @@ -708,4 +708,89 @@ describe('OpenAPI Merger - merging specs with conflicting components', () => { Spec2_SomeCallback: expect.anything(), }); }); + + it('prefixes discriminator mapping local references', async () => { + const spec1 = createOASDocument({ + info: { + title: 'Spec1', + version: '2023-10-31', + }, + paths: { + '/api/some_api': { + get: { + responses: { + '200': { + description: 'Successful response', + content: { + 'application/json': { + schema: { + oneOf: [ + { $ref: '#/components/schemas/Component1' }, + { $ref: '#/components/schemas/Component2' }, + ], + discriminator: { + propertyName: 'commonProp', + mapping: { + component1: '#/components/schemas/Component1', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + components: { + schemas: { + Component1: { + type: 'object', + properties: { + commonProp: { + type: 'string', + }, + extraProp1: { + type: 'boolean', + }, + }, + }, + Component2: { + type: 'object', + properties: { + commonProp: { + type: 'string', + }, + extraProp2: { + type: 'integer', + }, + }, + }, + }, + }, + }); + + const [mergedSpec] = Object.values( + await mergeSpecs({ + 1: spec1, + }) + ); + + expect(mergedSpec.paths['/api/some_api']?.get?.responses['200']).toMatchObject({ + content: { + 'application/json; Elastic-Api-Version=2023-10-31': { + schema: expect.objectContaining({ + discriminator: expect.objectContaining({ + mapping: { + component1: '#/components/schemas/Spec1_Component1', + }, + }), + }), + }, + }, + }); + expect(mergedSpec.components?.schemas).toMatchObject({ + Spec1_Component1: expect.anything(), + }); + }); }); diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts index 5e16aa47569dc..2ce584292dab9 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts @@ -27,7 +27,6 @@ describe('Service inventory - header filters', () => { specialServiceName, }) ); - cy.dismissServiceGroupsTour(); }); after(() => { diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts index 777f6f55cca0d..584e3e420eb19 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts @@ -103,7 +103,6 @@ describe('Service inventory', () => { it('when selecting a different time range and clicking the update button', () => { cy.wait(mainAliasNames); - cy.getByTestSubj('apmServiceGroupsTourDismissButton').click(); cy.selectAbsoluteTimeRange( moment(timeRange.rangeFrom).subtract(5, 'm').toISOString(), diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts index 746dd56678d06..a95b6ab7d7700 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts @@ -55,7 +55,6 @@ describe('service map', () => { it.skip('shows nodes in service map', () => { cy.visitKibana(serviceMapHref); cy.wait('@serviceMap'); - cy.getByTestSubj('apmServiceGroupsTourDismissButton').click(); prepareCanvasForScreenshot(); @@ -90,7 +89,6 @@ describe('service map', () => { it('shows empty state', () => { cy.visitKibana(serviceMapHref); // we need to dismiss the service-group call out first - cy.getByTestSubj('apmServiceGroupsTourDismissButton').click(); cy.getByTestSubj('apmUnifiedSearchBar').type('_id : foo{enter}'); cy.contains('No services available'); // search bar is still visible diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts index 1cfb68cdcfd57..ba1d8659e916e 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts @@ -133,16 +133,6 @@ Cypress.Commands.add('updateAdvancedSettings', (settings: Record { - window.localStorage.setItem( - 'apm.serviceGroupsTour', - JSON.stringify({ - createGroup: false, - editGroup: false, - }) - ); -}); - Cypress.Commands.add('withHidden', (selector, callback) => { cy.get(selector).invoke('attr', 'style', 'display: none'); callback(); diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts index f562d7c79f944..5b40ce38b2c3e 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts @@ -22,7 +22,6 @@ declare namespace Cypress { expectAPIsToHaveBeenCalledWith(params: { apisIntercepted: string[]; value: string }): void; updateAdvancedSettings(settings: Record): void; getByTestSubj(selector: string): Chainable>; - dismissServiceGroupsTour(): void; withHidden(selector: string, callback: () => void): void; } } diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_group_save/edit_button.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_group_save/edit_button.tsx index 0d763436318a6..c3af3d1c51902 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_group_save/edit_button.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_group_save/edit_button.tsx @@ -7,39 +7,23 @@ import { EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { ServiceGroupsTour } from '../service_groups_tour'; -import { useServiceGroupsTour } from '../use_service_groups_tour'; interface Props { onClick: () => void; } export function EditButton({ onClick }: Props) { - const { tourEnabled, dismissTour } = useServiceGroupsTour('editGroup'); return ( - { + onClick(); + }} > - { - dismissTour(); - onClick(); - }} - > - {i18n.translate('xpack.apm.serviceGroups.editGroupLabel', { - defaultMessage: 'Edit group', - })} - - + {i18n.translate('xpack.apm.serviceGroups.editGroupLabel', { + defaultMessage: 'Edit group', + })} + ); } diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_button_group.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_button_group.tsx index e1b801d0eadcb..3f023c24b7581 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_button_group.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_button_group.tsx @@ -8,8 +8,6 @@ import { EuiButtonGroup } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { useHistory } from 'react-router-dom'; -import { ServiceGroupsTour } from './service_groups_tour'; -import { useServiceGroupsTour } from './use_service_groups_tour'; const buttonGroupOptions = { allServices: { @@ -40,32 +38,18 @@ export function ServiceGroupsButtonGroup({ selectedNavButton: SelectedNavButton; }) { const history = useHistory(); - const { tourEnabled, dismissTour } = useServiceGroupsTour('createGroup'); return ( - { + const { pathname } = buttonGroupOptions[id as SelectedNavButton]; + history.push({ pathname }); + }} + legend={i18n.translate('xpack.apm.servicesGroups.buttonGroup.legend', { + defaultMessage: 'View all services or service groups', })} - content={i18n.translate('xpack.apm.serviceGroups.tour.createGroups.content', { - defaultMessage: - 'Group services together to build curated inventory views that remove noise and simplify investigations across services. Groups are Kibana space-specific and available for any users with appropriate access.', - })} - > - { - const { pathname } = buttonGroupOptions[id as SelectedNavButton]; - history.push({ pathname }); - }} - legend={i18n.translate('xpack.apm.servicesGroups.buttonGroup.legend', { - defaultMessage: 'View all services or service groups', - })} - /> - + /> ); } diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_tour.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_tour.tsx deleted file mode 100644 index 26473f2fae608..0000000000000 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/service_groups_tour.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButtonEmpty, - EuiSpacer, - EuiText, - EuiTourStep, - PopoverAnchorPosition, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React from 'react'; -import { ElasticDocsLink } from '../../shared/links/elastic_docs_link'; - -export type TourType = 'createGroup' | 'editGroup'; - -interface Props { - title: string; - content: string; - tourEnabled: boolean; - dismissTour: () => void; - anchorPosition?: PopoverAnchorPosition; - children: React.ReactElement; -} - -export function ServiceGroupsTour({ - tourEnabled, - dismissTour, - title, - content, - anchorPosition, - children, -}: Props) { - return ( - - {content} - - - {i18n.translate('xpack.apm.serviceGroups.tour.content.link.docs', { - defaultMessage: 'docs', - })} - - ), - }} - /> - - } - isStepOpen={tourEnabled} - onFinish={() => {}} - maxWidth={300} - minWidth={300} - step={1} - stepsTotal={1} - title={title} - anchorPosition={anchorPosition} - footerAction={ - - {i18n.translate('xpack.apm.serviceGroups.tour.dismiss', { - defaultMessage: 'Dismiss', - })} - - } - > - {children} - - ); -} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/use_service_groups_tour.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/use_service_groups_tour.tsx deleted file mode 100644 index 6a91d11d9325d..0000000000000 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_groups/use_service_groups_tour.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useLocalStorage } from '../../../hooks/use_local_storage'; -import { TourType } from './service_groups_tour'; - -const INITIAL_STATE: Record = { - createGroup: true, - editGroup: true, -}; - -export function useServiceGroupsTour(type: TourType) { - const [tourEnabled, setTourEnabled] = useLocalStorage('apm.serviceGroupsTour', INITIAL_STATE); - - return { - tourEnabled: tourEnabled[type], - dismissTour: () => - setTourEnabled({ - ...tourEnabled, - [type]: false, - }), - }; -} diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/entity_enablement/welcome_modal.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/entity_enablement/welcome_modal.tsx index 1bfab81231ea0..deba472b401c5 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/entity_enablement/welcome_modal.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/entity_enablement/welcome_modal.tsx @@ -95,7 +95,7 @@ export function Welcome({

{i18n.translate('xpack.apm.welcome.body', { defaultMessage: - 'You can now see services detected from logs alongside services instrumented with APM our new service inventory so you can view all of your services in a single place.', + 'You can now see services detected from logs alongside your APM-instrumented services in a single inventory so you can view all of your services in one place.', })}

diff --git a/x-pack/plugins/search_playground/public/components/chat.tsx b/x-pack/plugins/search_playground/public/components/chat.tsx index cc4c0b1ccdff2..b27955c326d23 100644 --- a/x-pack/plugins/search_playground/public/components/chat.tsx +++ b/x-pack/plugins/search_playground/public/components/chat.tsx @@ -56,7 +56,7 @@ export const Chat = () => { handleSubmit, getValues, } = useFormContext(); - const { messages, append, stop: stopRequest, setMessages, reload, error } = useChat(); + const { messages, append, stop: stopRequest, setMessages, reload } = useChat(); const messagesRef = useAutoBottomScroll(); const [isRegenerating, setIsRegenerating] = useState(false); const usageTracker = useUsageTracker(); @@ -88,8 +88,8 @@ export const Chat = () => { ); const isToolBarActionsDisabled = useMemo( - () => chatMessages.length <= 1 || !!error || isRegenerating || isSubmitting, - [chatMessages, error, isSubmitting, isRegenerating] + () => chatMessages.length <= 1 || isRegenerating || isSubmitting, + [chatMessages, isSubmitting, isRegenerating] ); const regenerateMessages = async () => { diff --git a/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts b/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts index 88a6052a0bbf7..13959e4455c29 100644 --- a/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts +++ b/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts @@ -305,6 +305,45 @@ describe('conversational chain', () => { }); }, 10000); + it('should omit the system messages in chat', async () => { + await createTestChain({ + responses: ['the final answer'], + chat: [ + { + id: '1', + role: MessageRole.user, + content: 'what is the work from home policy?', + }, + { + id: '2', + role: MessageRole.system, + content: 'Error occurred. Please try again.', + }, + ], + expectedFinalAnswer: 'the final answer', + expectedDocs: [ + { + documents: [ + { metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }, + { metadata: { _id: '1', _index: 'website' }, pageContent: 'value2' }, + ], + type: 'retrieved_docs', + }, + ], + expectedTokens: [ + { type: 'context_token_count', count: 15 }, + { type: 'prompt_token_count', count: 28 }, + ], + expectedSearchRequest: [ + { + method: 'POST', + path: '/index,website/_search', + body: { query: { match: { field: 'what is the work from home policy?' } }, size: 3 }, + }, + ], + }); + }, 10000); + it('should cope with quotes in the query', async () => { await createTestChain({ responses: ['rewrite "the" question', 'the final answer'], diff --git a/x-pack/plugins/search_playground/server/lib/conversational_chain.ts b/x-pack/plugins/search_playground/server/lib/conversational_chain.ts index f7b1634dd27b1..c63481e93c98f 100644 --- a/x-pack/plugins/search_playground/server/lib/conversational_chain.ts +++ b/x-pack/plugins/search_playground/server/lib/conversational_chain.ts @@ -18,7 +18,7 @@ import { createStreamDataTransformer, experimental_StreamData } from 'ai'; import { BaseLanguageModel } from '@langchain/core/language_models/base'; import { BaseMessage } from '@langchain/core/messages'; import { HumanMessage, AIMessage } from '@langchain/core/messages'; -import { ChatMessage, MessageRole } from '../types'; +import { ChatMessage } from '../types'; import { ElasticsearchRetriever } from './elasticsearch_retriever'; import { renderTemplate } from '../utils/render_template'; @@ -49,25 +49,28 @@ interface ContextInputs { question: string; } -const getSerialisedMessages = (chatHistory: ChatMessage[]) => { +const getSerialisedMessages = (chatHistory: BaseMessage[]) => { const formattedDialogueTurns = chatHistory.map((message) => { - if (message.role === MessageRole.user) { + if (message instanceof HumanMessage) { return `Human: ${message.content}`; - } else if (message.role === MessageRole.assistant) { + } else if (message instanceof AIMessage) { return `Assistant: ${message.content}`; } }); return formattedDialogueTurns.join('\n'); }; -const getMessages = (chatHistory: ChatMessage[]) => { - return chatHistory.map((message) => { - if (message.role === 'human') { - return new HumanMessage(message.content); - } else { - return new AIMessage(message.content); - } - }); +export const getMessages = (chatHistory: ChatMessage[]) => { + return chatHistory + .map((message) => { + if (message.role === 'human') { + return new HumanMessage(message.content); + } else if (message.role === 'assistant') { + return new AIMessage(message.content); + } + return null; + }) + .filter((message): message is BaseMessage => message !== null); }; const buildContext = (docs: Document[]) => { @@ -141,8 +144,9 @@ class ConversationalChainFn { const data = new experimental_StreamData(); const messages = msgs ?? []; - const previousMessages = messages.slice(0, -1); - const question = messages[messages.length - 1]!.content; + const lcMessages = getMessages(messages); + const previousMessages = lcMessages.slice(0, -1); + const question = lcMessages[lcMessages.length - 1]!.content; const retrievedDocs: Document[] = []; let retrievalChain: Runnable = RunnableLambda.from(() => ''); @@ -165,7 +169,7 @@ class ConversationalChainFn { return input.question; }); - if (previousMessages.length > 0) { + if (lcMessages.length > 1) { const questionRewritePromptTemplate = PromptTemplate.fromTemplate( this.options.questionRewritePrompt ); @@ -184,7 +188,6 @@ class ConversationalChainFn { }); } - const lcMessages = getMessages(messages); const prompt = ChatPromptTemplate.fromMessages([ SystemMessagePromptTemplate.fromTemplate(this.options.prompt), ...lcMessages, diff --git a/x-pack/plugins/search_playground/server/routes.ts b/x-pack/plugins/search_playground/server/routes.ts index de26776816f33..a71e650a8dae8 100644 --- a/x-pack/plugins/search_playground/server/routes.ts +++ b/x-pack/plugins/search_playground/server/routes.ts @@ -31,7 +31,7 @@ export function createRetriever(esQuery: string) { const query = JSON.parse(replacedQuery); return query; } catch (e) { - throw Error(e); + throw Error("Failed to parse the Elasticsearch Query. Check Query to make sure it's valid."); } }; } diff --git a/x-pack/plugins/security_solution/scripts/openapi/bundle_detections.js b/x-pack/plugins/security_solution/scripts/openapi/bundle_detections.js index e2df0d47f5b47..f79437c33222c 100644 --- a/x-pack/plugins/security_solution/scripts/openapi/bundle_detections.js +++ b/x-pack/plugins/security_solution/scripts/openapi/bundle_detections.js @@ -11,34 +11,36 @@ const { join, resolve } = require('path'); const ROOT = resolve(__dirname, '../..'); -bundle({ - sourceGlob: join(ROOT, 'common/api/detection_engine/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/serverless/security_solution_detections_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['serverless'], - specInfo: { - title: 'Security Solution Detections API (Elastic Cloud Serverless)', - description: - 'You can create rules that automatically turn events and external alerts sent to Elastic Security into detection alerts. These alerts are displayed on the Detections page.', +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'common/api/detection_engine/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_detections_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + specInfo: { + title: 'Security Solution Detections API (Elastic Cloud Serverless)', + description: + 'You can create rules that automatically turn events and external alerts sent to Elastic Security into detection alerts. These alerts are displayed on the Detections page.', + }, }, - }, -}); + }); -bundle({ - sourceGlob: join(ROOT, 'common/api/detection_engine/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/ess/security_solution_detections_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['ess'], - specInfo: { - title: 'Security Solution Detections API (Elastic Cloud and self-hosted)', - description: - 'You can create rules that automatically turn events and external alerts sent to Elastic Security into detection alerts. These alerts are displayed on the Detections page.', + await bundle({ + sourceGlob: join(ROOT, 'common/api/detection_engine/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_detections_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + specInfo: { + title: 'Security Solution Detections API (Elastic Cloud and self-hosted)', + description: + 'You can create rules that automatically turn events and external alerts sent to Elastic Security into detection alerts. These alerts are displayed on the Detections page.', + }, }, - }, -}); + }); +})(); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 62ce477ecca04..a528782abc0ec 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -10079,13 +10079,6 @@ "xpack.apm.serviceGroups.selectServicesList.nameColumnLabel": "Nom", "xpack.apm.serviceGroups.selectServicesList.notFoundLabel": "Aucun service disponible dans les dernières 24 heures. Vous pouvez toujours créer le groupe et les services qui correspondent à votre requête.", "xpack.apm.serviceGroups.sortLabel": "Trier", - "xpack.apm.serviceGroups.tour.content.link": "Découvrez plus d'informations dans le {docsLink}.", - "xpack.apm.serviceGroups.tour.content.link.docs": "documents", - "xpack.apm.serviceGroups.tour.createGroups.content": "Regroupez les services afin de créer des vues d'inventaire organisées qui éliminent le bruit et simplifient les enquêtes sur les services. Les groupes sont spécifiques à l'espace Kibana et sont disponibles pour tous les utilisateurs ayant un accès approprié.", - "xpack.apm.serviceGroups.tour.createGroups.title": "Présentation des groupes de services", - "xpack.apm.serviceGroups.tour.dismiss": "Rejeter", - "xpack.apm.serviceGroups.tour.editGroups.content": "Utilisez l'option de modification pour changer le nom, la requête ou les détails de ce groupe de services.", - "xpack.apm.serviceGroups.tour.editGroups.title": "Modifier ce groupe de services", "xpack.apm.serviceHealthStatus.critical": "Critique", "xpack.apm.serviceHealthStatus.healthy": "Intègre", "xpack.apm.serviceHealthStatus.unknown": "Inconnu", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index bba91c32ffc4c..6a3ba57b57fae 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -10042,13 +10042,6 @@ "xpack.apm.serviceGroups.selectServicesList.nameColumnLabel": "名前", "xpack.apm.serviceGroups.selectServicesList.notFoundLabel": "過去24時間以内にサービスはありません。グループを作成できます。クエリと一致するサービスが追加されます。", "xpack.apm.serviceGroups.sortLabel": "並べ替え", - "xpack.apm.serviceGroups.tour.content.link": "詳細は{docsLink}をご覧ください。", - "xpack.apm.serviceGroups.tour.content.link.docs": "ドキュメント", - "xpack.apm.serviceGroups.tour.createGroups.content": "サービスをグループ化し、ノイズを減らした編集済みのインベントリビューを作成し、サービス全体での調査を簡素化します。グループはKibanaスペース固有であり、適切なアクセス権のあるユーザーが使用できます。", - "xpack.apm.serviceGroups.tour.createGroups.title": "サービスグループの概要", - "xpack.apm.serviceGroups.tour.dismiss": "閉じる", - "xpack.apm.serviceGroups.tour.editGroups.content": "編集オプションを使用して、名前、クエリ、このサービスグループの詳細を変更します。", - "xpack.apm.serviceGroups.tour.editGroups.title": "このサービスグループを編集", "xpack.apm.serviceHealthStatus.critical": "重大", "xpack.apm.serviceHealthStatus.healthy": "正常", "xpack.apm.serviceHealthStatus.unknown": "不明", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b2fb6ec9b4f02..4051e74ceb544 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -10095,13 +10095,6 @@ "xpack.apm.serviceGroups.selectServicesList.nameColumnLabel": "名称", "xpack.apm.serviceGroups.selectServicesList.notFoundLabel": "过去 24 小时内没有服务可用。您仍然可以创建该组,并且会添加与您的查询匹配的服务。", "xpack.apm.serviceGroups.sortLabel": "排序", - "xpack.apm.serviceGroups.tour.content.link": "在{docsLink}中了解详情。", - "xpack.apm.serviceGroups.tour.content.link.docs": "文档", - "xpack.apm.serviceGroups.tour.createGroups.content": "将服务组合在一起以构建策展库存视图,进而跨服务消除噪音并简化调查。组特定于 Kibana 工作区,并且可用于任何具有适当访问权限的用户。", - "xpack.apm.serviceGroups.tour.createGroups.title": "服务组简介", - "xpack.apm.serviceGroups.tour.dismiss": "关闭", - "xpack.apm.serviceGroups.tour.editGroups.content": "使用编辑选项更改此服务组的名称、查询或详情。", - "xpack.apm.serviceGroups.tour.editGroups.title": "编辑此服务组", "xpack.apm.serviceHealthStatus.critical": "紧急", "xpack.apm.serviceHealthStatus.healthy": "运行正常", "xpack.apm.serviceHealthStatus.unknown": "未知",