diff --git a/src/platform/packages/shared/deeplinks/chat/constants.ts b/src/platform/packages/shared/deeplinks/chat/constants.ts index 7b2d993e658b..2c476dade23a 100644 --- a/src/platform/packages/shared/deeplinks/chat/constants.ts +++ b/src/platform/packages/shared/deeplinks/chat/constants.ts @@ -8,3 +8,4 @@ */ export const WORKCHAT_APP_ID = 'workchat'; +export const ONECHAT_APP_ID = 'onechat'; diff --git a/src/platform/packages/shared/deeplinks/chat/deep_links.ts b/src/platform/packages/shared/deeplinks/chat/deep_links.ts index 8a85e0023125..77e78ccf2059 100644 --- a/src/platform/packages/shared/deeplinks/chat/deep_links.ts +++ b/src/platform/packages/shared/deeplinks/chat/deep_links.ts @@ -7,10 +7,16 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { WORKCHAT_APP_ID } from './constants'; +import { ONECHAT_APP_ID, WORKCHAT_APP_ID } from './constants'; export type WorkchatApp = typeof WORKCHAT_APP_ID; +export type OnechatApp = typeof ONECHAT_APP_ID; export type WorkchatLinkId = 'agents' | 'integrations'; +export type OnechatLinkId = 'conversations' | 'tools'; -export type DeepLinkId = WorkchatApp | `${WorkchatApp}:${WorkchatLinkId}`; +export type DeepLinkId = + | WorkchatApp + | `${WorkchatApp}:${WorkchatLinkId}` + | OnechatApp + | `${OnechatApp}:${OnechatLinkId}`; diff --git a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts index 9834f7198f4b..4aad17343beb 100644 --- a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/schema.ts @@ -495,6 +495,14 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'onechat:ui:enabled': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'onechat:tools:enabled': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'banners:placement': { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts index 0b128789e4ac..7c6f3ba3dc22 100644 --- a/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/platform/plugins/private/kibana_usage_collection/server/collectors/management/types.ts @@ -50,6 +50,8 @@ export interface UsageStats { 'observability:aiAssistantSimulatedFunctionCalling': boolean; 'observability:aiAssistantSearchConnectorIndexPattern': string; 'onechat:mcpServer:enabled': boolean; + 'onechat:ui:enabled': boolean; + 'onechat:tools:enabled': boolean; 'visualization:heatmap:maxBuckets': number; 'visualization:regionmap:showWarnings': boolean; 'visualization:tileMap:maxPrecision': number; diff --git a/src/platform/plugins/shared/telemetry/schema/oss_platform.json b/src/platform/plugins/shared/telemetry/schema/oss_platform.json index aea1231ebb07..ff7e702c05ab 100644 --- a/src/platform/plugins/shared/telemetry/schema/oss_platform.json +++ b/src/platform/plugins/shared/telemetry/schema/oss_platform.json @@ -11039,6 +11039,18 @@ "description": "Non-default value of setting." } }, + "onechat:ui:enabled": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, + "onechat:tools:enabled": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "banners:placement": { "type": "keyword", "_meta": { diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 812a58f8c600..7aa30c8abcfa 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -109,6 +109,7 @@ "xpack.observabilityLogsOverview": [ "platform/packages/shared/logs-overview/src/components" ], + "xpack.onechat": ["platform/plugins/shared/onechat"], "xpack.osquery": [ "platform/plugins/shared/osquery" ], diff --git a/x-pack/platform/plugins/shared/onechat/common/constants.ts b/x-pack/platform/plugins/shared/onechat/common/constants.ts index af62660944f1..4c9323abfa9f 100644 --- a/x-pack/platform/plugins/shared/onechat/common/constants.ts +++ b/x-pack/platform/plugins/shared/onechat/common/constants.ts @@ -9,3 +9,13 @@ * UI Setting ID for enabling / disabling the MCP server */ export const ONECHAT_MCP_SERVER_UI_SETTING_ID = 'onechat:mcpServer:enabled'; + +/** + * UI Setting ID for enabling / disabling the onechat plugin UI + */ +export const ONECHAT_UI_SETTING_ID = 'onechat:ui:enabled'; + +/** + * UI Setting ID for enabling / disabling the tools UI + */ +export const ONECHAT_TOOLS_UI_SETTING_ID = 'onechat:tools:enabled'; diff --git a/x-pack/platform/plugins/shared/onechat/common/features.ts b/x-pack/platform/plugins/shared/onechat/common/features.ts index e24b822b1b08..20f2fd7866f5 100644 --- a/x-pack/platform/plugins/shared/onechat/common/features.ts +++ b/x-pack/platform/plugins/shared/onechat/common/features.ts @@ -7,7 +7,9 @@ export const ONECHAT_FEATURE_ID = 'onechat'; export const ONECHAT_FEATURE_NAME = 'onechat'; -export const ONECHAT_APP_ID = 'onechat_app'; +export const ONECHAT_APP_ID = 'onechat'; +export const ONECHAT_PATH = '/app/chat'; +export const ONECHAT_TITLE = 'Chat'; export const uiPrivileges = { show: 'show', diff --git a/x-pack/platform/plugins/shared/onechat/kibana.jsonc b/x-pack/platform/plugins/shared/onechat/kibana.jsonc index 2a2fb6abd03e..fae0ab93d580 100644 --- a/x-pack/platform/plugins/shared/onechat/kibana.jsonc +++ b/x-pack/platform/plugins/shared/onechat/kibana.jsonc @@ -10,7 +10,7 @@ "browser": true, "configPath": ["xpack", "onechat"], "requiredPlugins": ["actions", "inference", "features"], - "requiredBundles": [], + "requiredBundles": ["kibanaReact"], "optionalPlugins": [], "extraPublicDirs": [] } diff --git a/x-pack/platform/plugins/shared/onechat/public/application/components/tools/tools.tsx b/x-pack/platform/plugins/shared/onechat/public/application/components/tools/tools.tsx new file mode 100644 index 000000000000..d8d92d084d13 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/components/tools/tools.tsx @@ -0,0 +1,29 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; +import React from 'react'; +import { OnechatToolsTable } from './tools_table'; +export const OnechatTools = () => { + return ( + + + + + + + ); +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/components/tools/tools_table.tsx b/x-pack/platform/plugins/shared/onechat/public/application/components/tools/tools_table.tsx new file mode 100644 index 000000000000..18e2feddf980 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/components/tools/tools_table.tsx @@ -0,0 +1,83 @@ +/* + * 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 { EuiBadge, EuiBadgeGroup, EuiBasicTable, EuiBasicTableColumn, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ToolDescriptor } from '@kbn/onechat-common'; +import React from 'react'; +import { useOnechatTools } from '../../hooks/use_tools'; + +const parseToolDescription = (description: string): string => { + // Truncate at newline + const [truncatedDescription] = description.split('\n'); + return truncatedDescription; +}; + +const columns: Array> = [ + { + field: 'id', + name: i18n.translate('xpack.onechat.tools.toolIdLabel', { defaultMessage: 'Tool' }), + valign: 'top', + render: (id: string) => ( + + {id} + + ), + }, + { + field: 'description', + name: i18n.translate('xpack.onechat.tools.toolDescriptionLabel', { + defaultMessage: 'Description', + }), + width: '60%', + valign: 'top', + render: (description: string) => { + return {parseToolDescription(description)}; + }, + }, + { + field: 'meta.tags', + name: i18n.translate('xpack.onechat.tools.tagsLabel', { + defaultMessage: 'Tags', + }), + width: '15%', + valign: 'top', + render: (tags: string[]) => { + return ( + + {tags.map((tag) => ( + + {tag} + + ))} + + ); + }, + }, +]; + +export const OnechatToolsTable: React.FC = () => { + const { tools, isLoading, error } = useOnechatTools(); + const errorMessage = error + ? i18n.translate('xpack.onechat.tools.listToolsErrorMessage', { + defaultMessage: 'Failed to fetch tools', + }) + : undefined; + + return ( + + ); +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/context/onechat_services_context.tsx b/x-pack/platform/plugins/shared/onechat/public/application/context/onechat_services_context.tsx new file mode 100644 index 000000000000..6b5e81566dda --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/context/onechat_services_context.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createContext } from 'react'; +import { OnechatInternalService } from '../../services'; + +export const OnechatServicesContext = createContext(undefined); diff --git a/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_breadcrumbs.ts b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_breadcrumbs.ts new file mode 100644 index 000000000000..5b6b7ae9d590 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_breadcrumbs.ts @@ -0,0 +1,61 @@ +/* + * 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 { useEffect, useMemo, useCallback } from 'react'; +import type { ChromeBreadcrumb } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; +import { ONECHAT_APP_ID } from '../../../common/features'; +import { useKibana } from './use_kibana'; + +interface OnechatBreadcrumb { + text: string; + path?: string; +} + +export const useBreadcrumb = (breadcrumbs: OnechatBreadcrumb[]) => { + const { + services: { chrome, application }, + } = useKibana(); + + const getUrl = useCallback( + (path: string) => { + return application.getUrlForApp(ONECHAT_APP_ID, { path }); + }, + [application] + ); + + const appUrl = useMemo(() => { + return getUrl(''); + }, [getUrl]); + + const baseCrumbs: ChromeBreadcrumb[] = useMemo(() => { + return [ + { + text: i18n.translate('xpack.onechat.breadcrumb.onechat', { + defaultMessage: 'OneChat', + }), + href: appUrl, + }, + ]; + }, [appUrl]); + + useEffect(() => { + const additionalCrumbs = breadcrumbs.map((crumb) => { + return { + text: crumb.text, + href: crumb.path ? getUrl(crumb.path) : undefined, + }; + }); + + chrome.setBreadcrumbs([...baseCrumbs, ...additionalCrumbs], { + project: { value: additionalCrumbs.length ? additionalCrumbs : baseCrumbs, absolute: true }, + }); + return () => { + chrome.setBreadcrumbs([]); + }; + }, [chrome, baseCrumbs, breadcrumbs, getUrl]); +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_kibana.ts b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_kibana.ts new file mode 100644 index 000000000000..ee5bb66a4a6e --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_kibana.ts @@ -0,0 +1,18 @@ +/* + * 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 { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { CoreStart } from '@kbn/core/public'; +import type { OnechatStartDependencies } from '../../types'; + +export type StartServices = CoreStart & { + plugins: OnechatStartDependencies; +}; + +const useTypedKibana = () => useKibana(); + +export { useTypedKibana as useKibana }; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_onechat_service.ts b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_onechat_service.ts new file mode 100644 index 000000000000..8af5f74313c8 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_onechat_service.ts @@ -0,0 +1,19 @@ +/* + * 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 { useContext } from 'react'; +import { OnechatServicesContext } from '../context/onechat_services_context'; + +export const useOnechatServices = () => { + const services = useContext(OnechatServicesContext); + if (services === undefined) { + throw new Error( + `OnechatServicesContext not set. Did you wrap your component in ?` + ); + } + return services; +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_tools.ts b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_tools.ts new file mode 100644 index 000000000000..6748fbb838f9 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/hooks/use_tools.ts @@ -0,0 +1,20 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; +import { useOnechatServices } from './use_onechat_service'; + +export const useOnechatTools = () => { + const { toolsService } = useOnechatServices(); + + const { data, isLoading, error } = useQuery({ + queryKey: ['tools', 'list'], + queryFn: () => toolsService.list(), + }); + + return { tools: data?.tools ?? [], isLoading, error }; +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/index.ts b/x-pack/platform/plugins/shared/onechat/public/application/index.ts new file mode 100644 index 000000000000..67a4c671aca9 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { mountApp } from './mount'; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/mount.tsx b/x-pack/platform/plugins/shared/onechat/public/application/mount.tsx new file mode 100644 index 000000000000..6466e0cf7f1c --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/mount.tsx @@ -0,0 +1,59 @@ +/* + * 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 { CoreStart, ScopedHistory } from '@kbn/core/public'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { I18nProvider } from '@kbn/i18n-react'; +import { Router } from '@kbn/shared-ux-router'; +import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import { OnechatRoutes } from './routes'; +import type { OnechatInternalService } from '../services'; +import { OnechatStartDependencies } from '../types'; +import { OnechatServicesContext } from './context/onechat_services_context'; + +export const mountApp = async ({ + core, + plugins, + element, + history, + services, +}: { + core: CoreStart; + plugins: OnechatStartDependencies; + element: HTMLElement; + history: ScopedHistory; + services: OnechatInternalService; +}) => { + const kibanaServices = { ...core, plugins }; + const queryClient = new QueryClient(); + + ReactDOM.render( + core.rendering.addContext( + + + + + + + + + + + + + + ), + element + ); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/pages/chat.tsx b/x-pack/platform/plugins/shared/onechat/public/application/pages/chat.tsx new file mode 100644 index 000000000000..847569dfe59a --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/pages/chat.tsx @@ -0,0 +1,12 @@ +/* + * 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 React from 'react'; + +export const OnechatConversationsPage = () => { + return
OnechatConversationsPage
; +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/pages/tools.tsx b/x-pack/platform/plugins/shared/onechat/public/application/pages/tools.tsx new file mode 100644 index 000000000000..8760b8e17ccf --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/pages/tools.tsx @@ -0,0 +1,19 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React from 'react'; +import { OnechatTools } from '../components/tools/tools'; +import { useBreadcrumb } from '../hooks/use_breadcrumbs'; + +export const OnechatToolsPage = () => { + useBreadcrumb([ + { text: i18n.translate('xpack.onechat.chat.title', { defaultMessage: 'Chat' }) }, + { text: i18n.translate('xpack.onechat.tools.title', { defaultMessage: 'Tools' }) }, + ]); + return ; +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/application/routes.tsx b/x-pack/platform/plugins/shared/onechat/public/application/routes.tsx new file mode 100644 index 000000000000..a8f9e50e6ed1 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/application/routes.tsx @@ -0,0 +1,29 @@ +/* + * 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 { Routes, Route } from '@kbn/shared-ux-router'; +import React from 'react'; +import { useUiSetting } from '@kbn/kibana-react-plugin/public'; +import { OnechatToolsPage } from './pages/tools'; +import { OnechatConversationsPage } from './pages/chat'; +import { ONECHAT_TOOLS_UI_SETTING_ID } from '../../common/constants'; + +export const OnechatRoutes: React.FC<{}> = () => { + const isToolsPageEnabled = useUiSetting(ONECHAT_TOOLS_UI_SETTING_ID, false); + return ( + + + + + {isToolsPageEnabled && ( + + + + )} + + ); +}; diff --git a/x-pack/platform/plugins/shared/onechat/public/plugin.tsx b/x-pack/platform/plugins/shared/onechat/public/plugin.tsx index e7c7f974ed30..b72629563f3d 100644 --- a/x-pack/platform/plugins/shared/onechat/public/plugin.tsx +++ b/x-pack/platform/plugins/shared/onechat/public/plugin.tsx @@ -5,8 +5,21 @@ * 2.0. */ -import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; +import { + type CoreSetup, + type CoreStart, + type Plugin, + type PluginInitializerContext, +} from '@kbn/core/public'; import type { Logger } from '@kbn/logging'; +import { registerApp } from './register'; +import { + AgentService, + ChatService, + ConversationsService, + OnechatInternalService, + ToolsService, +} from './services'; import type { ConfigSchema, OnechatPluginSetup, @@ -14,13 +27,7 @@ import type { OnechatSetupDependencies, OnechatStartDependencies, } from './types'; -import { - AgentService, - ChatService, - ConversationsService, - ToolsService, - OnechatInternalService, -} from './services'; +import { ONECHAT_UI_SETTING_ID } from '../common/constants'; export class OnechatPlugin implements @@ -32,16 +39,25 @@ export class OnechatPlugin > { logger: Logger; - // @ts-expect-error unused for now private internalServices?: OnechatInternalService; constructor(context: PluginInitializerContext) { this.logger = context.logger.get(); } - setup( - coreSetup: CoreSetup, - pluginsSetup: OnechatSetupDependencies - ): OnechatPluginSetup { + setup(core: CoreSetup): OnechatPluginSetup { + const isOnechatUiEnabled = core.uiSettings.get(ONECHAT_UI_SETTING_ID, false); + + if (isOnechatUiEnabled) { + registerApp({ + core, + getServices: () => { + if (!this.internalServices) { + throw new Error('getServices called before plugin start'); + } + return this.internalServices; + }, + }); + } return {}; } diff --git a/x-pack/platform/plugins/shared/onechat/public/register.ts b/x-pack/platform/plugins/shared/onechat/public/register.ts new file mode 100644 index 000000000000..fd30ce733232 --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/public/register.ts @@ -0,0 +1,60 @@ +/* + * 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 { CoreSetup } from '@kbn/core-lifecycle-browser'; +import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; +import { AppMountParameters } from '@kbn/core-application-browser'; +import { i18n } from '@kbn/i18n'; +import { OnechatInternalService } from './services'; +import { OnechatPluginStart } from './types'; +import { ONECHAT_APP_ID, ONECHAT_PATH, ONECHAT_TITLE } from '../common/features'; +import { ONECHAT_TOOLS_UI_SETTING_ID } from '../common/constants'; + +export const registerApp = ({ + core, + getServices, +}: { + core: CoreSetup; + getServices: () => OnechatInternalService; +}) => { + const isToolsPageEnabled = core.uiSettings.get(ONECHAT_TOOLS_UI_SETTING_ID, false); + core.application.register({ + id: ONECHAT_APP_ID, + appRoute: ONECHAT_PATH, + category: DEFAULT_APP_CATEGORIES.chat, + title: ONECHAT_TITLE, + euiIconType: 'logoElasticsearch', + visibleIn: ['sideNav', 'globalSearch'], + deepLinks: [ + { + id: 'conversations', + path: '/conversations', + title: i18n.translate('xpack.onechat.chat.conversationsTitle', { + defaultMessage: 'Conversations', + }), + }, + ...(isToolsPageEnabled + ? [ + { + id: 'tools', + path: '/tools', + title: i18n.translate('xpack.onechat.tools.title', { defaultMessage: 'Tools' }), + }, + ] + : []), + ], + async mount({ element, history }: AppMountParameters) { + const { mountApp } = await import('./application'); + const [coreStart, startPluginDeps] = await core.getStartServices(); + + coreStart.chrome.docTitle.change(ONECHAT_TITLE); + const services = getServices(); + + return mountApp({ core: coreStart, services, element, history, plugins: startPluginDeps }); + }, + }); +}; diff --git a/x-pack/platform/plugins/shared/onechat/server/plugin.ts b/x-pack/platform/plugins/shared/onechat/server/plugin.ts index 321a18cbb682..6764556e9c7e 100644 --- a/x-pack/platform/plugins/shared/onechat/server/plugin.ts +++ b/x-pack/platform/plugins/shared/onechat/server/plugin.ts @@ -5,22 +5,20 @@ * 2.0. */ -import type { Logger } from '@kbn/logging'; import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server'; -import { i18n } from '@kbn/i18n'; -import { schema } from '@kbn/config-schema'; +import type { Logger } from '@kbn/logging'; import type { OnechatConfig } from './config'; +import { registerFeatures } from './features'; +import { registerRoutes } from './routes'; +import { ServiceManager } from './services'; +import { registerTools } from './tools'; import type { OnechatPluginSetup, OnechatPluginStart, OnechatSetupDependencies, OnechatStartDependencies, } from './types'; -import { registerRoutes } from './routes'; -import { ServiceManager } from './services'; -import { registerFeatures } from './features'; -import { registerTools } from './tools'; -import { ONECHAT_MCP_SERVER_UI_SETTING_ID } from '../common/constants'; +import { registerUISettings } from './ui_settings'; export class OnechatPlugin implements @@ -53,20 +51,7 @@ export class OnechatPlugin registerTools({ tools: serviceSetups.tools }); - coreSetup.uiSettings.register({ - [ONECHAT_MCP_SERVER_UI_SETTING_ID]: { - description: i18n.translate('onechat.uiSettings.mcpServer.description', { - defaultMessage: 'Enables MCP server with access to tools.', - }), - name: i18n.translate('onechat.uiSettings.mcpServer.name', { - defaultMessage: 'MCP Server', - }), - schema: schema.boolean(), - value: false, - readonly: true, - readonlyMode: 'ui', - }, - }); + registerUISettings({ uiSettings: coreSetup.uiSettings }); const router = coreSetup.http.createRouter(); registerRoutes({ diff --git a/x-pack/platform/plugins/shared/onechat/server/ui_settings.ts b/x-pack/platform/plugins/shared/onechat/server/ui_settings.ts new file mode 100644 index 000000000000..08401984e99d --- /dev/null +++ b/x-pack/platform/plugins/shared/onechat/server/ui_settings.ts @@ -0,0 +1,56 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { UiSettingsServiceSetup } from '@kbn/core-ui-settings-server'; +import { i18n } from '@kbn/i18n'; +import { + ONECHAT_UI_SETTING_ID, + ONECHAT_MCP_SERVER_UI_SETTING_ID, + ONECHAT_TOOLS_UI_SETTING_ID, +} from '../common/constants'; + +export const registerUISettings = ({ uiSettings }: { uiSettings: UiSettingsServiceSetup }) => { + uiSettings.register({ + [ONECHAT_MCP_SERVER_UI_SETTING_ID]: { + description: i18n.translate('xpack.onechat.uiSettings.mcpServer.description', { + defaultMessage: 'Enables MCP server with access to tools.', + }), + name: i18n.translate('xpack.onechat.uiSettings.mcpServer.name', { + defaultMessage: 'MCP Server', + }), + schema: schema.boolean(), + value: false, + readonly: true, + readonlyMode: 'ui', + }, + [ONECHAT_UI_SETTING_ID]: { + description: i18n.translate('xpack.onechat.uiSettings.chatUI.description', { + defaultMessage: 'Enables the OneChat chat UI.', + }), + name: i18n.translate('xpack.onechat.uiSettings.chatUI.name', { + defaultMessage: 'OneChat Chat UI', + }), + schema: schema.boolean(), + value: false, + readonly: true, + readonlyMode: 'ui', + }, + [ONECHAT_TOOLS_UI_SETTING_ID]: { + description: i18n.translate('xpack.onechat.uiSettings.toolsPage.description', { + defaultMessage: 'Enables the OneChat tools page.', + }), + name: i18n.translate('xpack.onechat.uiSettings.toolsPage.name', { + defaultMessage: 'OneChat Tools Page', + }), + schema: schema.boolean(), + value: false, + readonly: true, + readonlyMode: 'ui', + }, + }); +}; diff --git a/x-pack/platform/plugins/shared/onechat/tsconfig.json b/x-pack/platform/plugins/shared/onechat/tsconfig.json index 873cacd519da..9d8a1af52cca 100644 --- a/x-pack/platform/plugins/shared/onechat/tsconfig.json +++ b/x-pack/platform/plugins/shared/onechat/tsconfig.json @@ -37,6 +37,15 @@ "@kbn/features-plugin", "@kbn/core-logging-server-mocks", "@kbn/i18n", - "@kbn/onechat-genai-utils" + "@kbn/onechat-genai-utils", + "@kbn/shared-ux-page-kibana-template", + "@kbn/kibana-react-plugin", + "@kbn/i18n-react", + "@kbn/shared-ux-router", + "@kbn/shared-ux-link-redirect-app", + "@kbn/core-lifecycle-browser", + "@kbn/core-application-common", + "@kbn/core-application-browser", + "@kbn/core-ui-settings-server" ] } diff --git a/x-pack/solutions/search/plugins/serverless_search/kibana.jsonc b/x-pack/solutions/search/plugins/serverless_search/kibana.jsonc index 6c54ba1a752e..52994287f264 100644 --- a/x-pack/solutions/search/plugins/serverless_search/kibana.jsonc +++ b/x-pack/solutions/search/plugins/serverless_search/kibana.jsonc @@ -30,9 +30,10 @@ "serverless", "searchHomepage", "share", - "visualizations" + "visualizations", ], "optionalPlugins": [ + "onechat", "indexManagement", "contentConnectors", "searchInferenceEndpoints", diff --git a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts index dbb337cbf47e..beed831e91a6 100644 --- a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts @@ -44,6 +44,20 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio { link: 'discover', }, + { + title: i18n.translate('xpack.serverlessSearch.nav.chat', { + defaultMessage: 'Chat', + }), + renderAs: 'accordion', + children: [ + { + link: 'onechat:conversations', + }, + { + link: 'onechat:tools', + }, + ], + }, { link: 'dashboards', getIsActive: ({ pathNameSerialized, prepend }) => {