From 1f7e40bc2fe37b175ea463389e0307fbf3e12f11 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 2 Sep 2024 16:21:26 +0200 Subject: [PATCH 01/36] Prepare api-key plugin configuration --- x-pack/plugins/api_key/README.md | 1 + x-pack/plugins/api_key/common/index.ts | 10 ++++ x-pack/plugins/api_key/jest.config.js | 15 ++++++ x-pack/plugins/api_key/kibana.jsonc | 19 +++++++ x-pack/plugins/api_key/public/index.ts | 14 +++++ x-pack/plugins/api_key/public/plugin.ts | 26 +++++++++ x-pack/plugins/api_key/public/use_api_key.ts | 57 ++++++++++++++++++++ x-pack/plugins/api_key/server/index.ts | 15 ++++++ x-pack/plugins/api_key/server/plugin.ts | 34 ++++++++++++ x-pack/plugins/api_key/tsconfig.json | 48 +++++++++++++++++ 10 files changed, 239 insertions(+) create mode 100644 x-pack/plugins/api_key/README.md create mode 100644 x-pack/plugins/api_key/common/index.ts create mode 100644 x-pack/plugins/api_key/jest.config.js create mode 100644 x-pack/plugins/api_key/kibana.jsonc create mode 100644 x-pack/plugins/api_key/public/index.ts create mode 100644 x-pack/plugins/api_key/public/plugin.ts create mode 100644 x-pack/plugins/api_key/public/use_api_key.ts create mode 100644 x-pack/plugins/api_key/server/index.ts create mode 100644 x-pack/plugins/api_key/server/plugin.ts create mode 100644 x-pack/plugins/api_key/tsconfig.json diff --git a/x-pack/plugins/api_key/README.md b/x-pack/plugins/api_key/README.md new file mode 100644 index 0000000000000..36023b59ef859 --- /dev/null +++ b/x-pack/plugins/api_key/README.md @@ -0,0 +1 @@ +# API KEY PLUGIN diff --git a/x-pack/plugins/api_key/common/index.ts b/x-pack/plugins/api_key/common/index.ts new file mode 100644 index 0000000000000..3540929f65d63 --- /dev/null +++ b/x-pack/plugins/api_key/common/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PLUGIN_ID = 'apiKey'; +export const PLUGIN_NAME = 'ApiKey'; +export const PLUGIN_PATH = '/app/api_key'; diff --git a/x-pack/plugins/api_key/jest.config.js b/x-pack/plugins/api_key/jest.config.js new file mode 100644 index 0000000000000..d23d0d55128b5 --- /dev/null +++ b/x-pack/plugins/api_key/jest.config.js @@ -0,0 +1,15 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/plugins/search_playground'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_playground', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/x-pack/plugins/search_playground/{public,server}/**/*.{ts,tsx}'], +}; diff --git a/x-pack/plugins/api_key/kibana.jsonc b/x-pack/plugins/api_key/kibana.jsonc new file mode 100644 index 0000000000000..9b09493a8f77e --- /dev/null +++ b/x-pack/plugins/api_key/kibana.jsonc @@ -0,0 +1,19 @@ +{ + "type": "plugin", + "id": "@kbn/api-key", + "owner": "@elastic/search-kibana", + "plugin": { + "id": "apiKey", + "server": true, + "browser": true, + "configPath": [ + "xpack" + ], + "requiredPlugins": [ + ], + "optionalPlugins": [ + ], + "requiredBundles": [ + ] + } +} diff --git a/x-pack/plugins/api_key/public/index.ts b/x-pack/plugins/api_key/public/index.ts new file mode 100644 index 0000000000000..7ae4e8e376a49 --- /dev/null +++ b/x-pack/plugins/api_key/public/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { PluginInitializerContext } from '@kbn/core/public'; + +import { ApiKeyPlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new ApiKeyPlugin(initializerContext); +} diff --git a/x-pack/plugins/api_key/public/plugin.ts b/x-pack/plugins/api_key/public/plugin.ts new file mode 100644 index 0000000000000..4645275a7afd0 --- /dev/null +++ b/x-pack/plugins/api_key/public/plugin.ts @@ -0,0 +1,26 @@ +/* + * 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 type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public'; + +interface ApiKeyPluginSetup {} +interface ApiKeyPluginStart {} + +export class ApiKeyPlugin implements Plugin { + constructor(initializerContext: PluginInitializerContext) {} + + public setup( + core: CoreSetup, + deps: AppPluginSetupDependencies + ): ApiKeyPluginSetup { + return {}; + } + + public start() {} + + public stop() {} +} diff --git a/x-pack/plugins/api_key/public/use_api_key.ts b/x-pack/plugins/api_key/public/use_api_key.ts new file mode 100644 index 0000000000000..f1b4c81939892 --- /dev/null +++ b/x-pack/plugins/api_key/public/use_api_key.ts @@ -0,0 +1,57 @@ +/* + * 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 { useState, useEffect } from 'react'; + +export const useApiKey = (key) => { + const [apiKey, setApiKey] = useState(null); + const [isKeyLoaded, setIsKeyLoaded] = useState(false); + + useEffect(() => { + const storedKey = sessionStorage.getItem(key); + if (storedKey) { + setApiKey(storedKey); + setIsKeyLoaded(true); + } + }, [key]); + + const fetchApiKey = async () => { + const response = await fetch('/api/generate-key', { + method: 'POST', + body: JSON.stringify({ key }), + }); + const data = await response.json(); + return data.apiKey; + }; + + const resetKey = () => { + sessionStorage.removeItem(key); + setApiKey(null); + refetch(); + }; + + const createApiKey = async (newKeyData) => { + if (!apiKey) return; + const response = await fetch('/api/create-key', { + method: 'POST', + body: JSON.stringify({ key, ...newKeyData }), + }); + const data = await response.json(); + + return data; + }; + + const getApiKeyPreview = () => { + return apiKey ? `${apiKey.slice(0, 10)}**********` : ''; + }; + + return { + apiKey, + resetKey, + getApiKeyPreview, + createApiKey, + }; +}; diff --git a/x-pack/plugins/api_key/server/index.ts b/x-pack/plugins/api_key/server/index.ts new file mode 100644 index 0000000000000..0e8b60d0def85 --- /dev/null +++ b/x-pack/plugins/api_key/server/index.ts @@ -0,0 +1,15 @@ +/* + * 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 { PluginInitializerContext } from '@kbn/core/server'; + +export { config } from './config'; + +export async function plugin(initializerContext: PluginInitializerContext) { + const { ApiKeyPlugin } = await import('./plugin'); + return new ApiKeyPlugin(initializerContext); +} diff --git a/x-pack/plugins/api_key/server/plugin.ts b/x-pack/plugins/api_key/server/plugin.ts new file mode 100644 index 0000000000000..0253a6b29a5ea --- /dev/null +++ b/x-pack/plugins/api_key/server/plugin.ts @@ -0,0 +1,34 @@ +/* + * 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; +import { defineRoutes } from './routes'; + +export class ApiKeyPlugin + implements Plugin +{ + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('apiKey plugin: Setup'); + const router = core.http.createRouter(); + + defineRoutes({ router, logger: this.logger, getStartServices: core.getStartServices }); + + return {}; + } + + public start(core: CoreStart) { + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/api_key/tsconfig.json b/x-pack/plugins/api_key/tsconfig.json new file mode 100644 index 0000000000000..dc481d35327f2 --- /dev/null +++ b/x-pack/plugins/api_key/tsconfig.json @@ -0,0 +1,48 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + }, + "include": [ + "__mocks__/**/*", + "common/**/*", + "public/**/*", + "server/**/*", + ], + "kbn_references": [ + "@kbn/config-schema", + "@kbn/core", + "@kbn/core-elasticsearch-server", + "@kbn/core-http-browser", + "@kbn/i18n", + "@kbn/i18n-react", + "@kbn/kibana-react-plugin", + "@kbn/security-plugin", + "@kbn/user-profile-components", + "@kbn/shared-ux-router", + "@kbn/shared-ux-page-kibana-template", + "@kbn/navigation-plugin", + "@kbn/core-http-server", + "@kbn/share-plugin", + "@kbn/cloud-plugin", + "@kbn/actions-plugin", + "@kbn/shared-ux-utility", + "@kbn/core-lifecycle-browser", + "@kbn/stack-connectors-plugin", + "@kbn/cases-plugin", + "@kbn/triggers-actions-ui-plugin", + "@kbn/langchain", + "@kbn/logging", + "@kbn/react-kibana-context-render", + "@kbn/doc-links", + "@kbn/core-logging-server-mocks", + "@kbn/analytics", + "@kbn/usage-collection-plugin", + "@kbn/console-plugin", + "@kbn/utility-types", + "@kbn/kibana-utils-plugin" + ], + "exclude": [ + "target/**/*", + ] +} From 7e33030e4432a4850186cba9cd55d300be61eb8f Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 2 Sep 2024 19:55:50 +0100 Subject: [PATCH 02/36] WIP --- .github/CODEOWNERS | 1 + package.json | 1 + tsconfig.base.json | 2 + x-pack/.i18nrc.json | 1 + x-pack/plugins/api_key/README.md | 1 - x-pack/plugins/api_key/public/plugin.ts | 26 ----------- x-pack/plugins/api_key/server/plugin.ts | 34 -------------- x-pack/plugins/search_api_keys/README.md | 3 ++ .../common/index.ts | 4 +- .../plugins/search_api_keys/common/types.ts | 13 ++++++ .../jest.config.js | 0 .../{api_key => search_api_keys}/kibana.jsonc | 15 +++---- .../public/index.ts | 0 .../plugins/search_api_keys/public/plugin.ts | 23 ++++++++++ .../public/use_api_key.ts | 0 .../plugins/search_api_keys/server/config.ts | 19 ++++++++ .../server/index.ts | 6 +-- .../search_api_keys/server/lib/privileges.ts | 45 +++++++++++++++++++ .../plugins/search_api_keys/server/plugin.ts | 45 +++++++++++++++++++ .../search_api_keys/server/routes/routes.ts | 33 ++++++++++++++ .../plugins/search_api_keys/server/types.ts | 17 +++++++ .../tsconfig.json | 0 x-pack/plugins/serverless_search/kibana.jsonc | 2 +- yarn.lock | 4 ++ 24 files changed, 219 insertions(+), 76 deletions(-) delete mode 100644 x-pack/plugins/api_key/README.md delete mode 100644 x-pack/plugins/api_key/public/plugin.ts delete mode 100644 x-pack/plugins/api_key/server/plugin.ts create mode 100644 x-pack/plugins/search_api_keys/README.md rename x-pack/plugins/{api_key => search_api_keys}/common/index.ts (77%) create mode 100644 x-pack/plugins/search_api_keys/common/types.ts rename x-pack/plugins/{api_key => search_api_keys}/jest.config.js (100%) rename x-pack/plugins/{api_key => search_api_keys}/kibana.jsonc (53%) rename x-pack/plugins/{api_key => search_api_keys}/public/index.ts (100%) create mode 100644 x-pack/plugins/search_api_keys/public/plugin.ts rename x-pack/plugins/{api_key => search_api_keys}/public/use_api_key.ts (100%) create mode 100644 x-pack/plugins/search_api_keys/server/config.ts rename x-pack/plugins/{api_key => search_api_keys}/server/index.ts (72%) create mode 100644 x-pack/plugins/search_api_keys/server/lib/privileges.ts create mode 100644 x-pack/plugins/search_api_keys/server/plugin.ts create mode 100644 x-pack/plugins/search_api_keys/server/routes/routes.ts create mode 100644 x-pack/plugins/search_api_keys/server/types.ts rename x-pack/plugins/{api_key => search_api_keys}/tsconfig.json (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cbffef0027017..4a14d682e6349 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -747,6 +747,7 @@ packages/kbn-search-errors @elastic/kibana-data-discovery examples/search_examples @elastic/kibana-data-discovery x-pack/plugins/search_homepage @elastic/search-kibana packages/kbn-search-index-documents @elastic/search-kibana +x-pack/plugins/search_api_keys @elastic/search-kibana x-pack/plugins/search_indices @elastic/search-kibana x-pack/plugins/search_inference_endpoints @elastic/search-kibana x-pack/plugins/search_notebooks @elastic/search-kibana diff --git a/package.json b/package.json index 99ad13f9b289b..43133c8d1f9cd 100644 --- a/package.json +++ b/package.json @@ -756,6 +756,7 @@ "@kbn/screenshotting-example-plugin": "link:x-pack/examples/screenshotting_example", "@kbn/screenshotting-plugin": "link:x-pack/plugins/screenshotting", "@kbn/screenshotting-server": "link:packages/kbn-screenshotting-server", + "@kbn/search-api-keys": "link:x-pack/plugins/search_api_keys", "@kbn/search-api-panels": "link:packages/kbn-search-api-panels", "@kbn/search-assistant": "link:x-pack/plugins/search_assistant", "@kbn/search-connectors": "link:packages/kbn-search-connectors", diff --git a/tsconfig.base.json b/tsconfig.base.json index 44bb897bea1c2..ce32576733310 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1472,6 +1472,8 @@ "@kbn/screenshotting-plugin/*": ["x-pack/plugins/screenshotting/*"], "@kbn/screenshotting-server": ["packages/kbn-screenshotting-server"], "@kbn/screenshotting-server/*": ["packages/kbn-screenshotting-server/*"], + "@kbn/search-api-keys": ["x-pack/plugins/search_api_keys"], + "@kbn/search-api-keys/*": ["x-pack/plugins/search_api_keys/*"], "@kbn/search-api-panels": ["packages/kbn-search-api-panels"], "@kbn/search-api-panels/*": ["packages/kbn-search-api-panels/*"], "@kbn/search-assistant": ["x-pack/plugins/search_assistant"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index f2ab7a782915e..0c37533d79d03 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -101,6 +101,7 @@ "xpack.rollupJobs": ["packages/rollup", "plugins/rollup"], "xpack.runtimeFields": "plugins/runtime_fields", "xpack.screenshotting": "plugins/screenshotting", + "xpack.searchApiKeys": "plugins/search_api_keys", "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchIndices": "plugins/search_indices", "xpack.searchNotebooks": "plugins/search_notebooks", diff --git a/x-pack/plugins/api_key/README.md b/x-pack/plugins/api_key/README.md deleted file mode 100644 index 36023b59ef859..0000000000000 --- a/x-pack/plugins/api_key/README.md +++ /dev/null @@ -1 +0,0 @@ -# API KEY PLUGIN diff --git a/x-pack/plugins/api_key/public/plugin.ts b/x-pack/plugins/api_key/public/plugin.ts deleted file mode 100644 index 4645275a7afd0..0000000000000 --- a/x-pack/plugins/api_key/public/plugin.ts +++ /dev/null @@ -1,26 +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 type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public'; - -interface ApiKeyPluginSetup {} -interface ApiKeyPluginStart {} - -export class ApiKeyPlugin implements Plugin { - constructor(initializerContext: PluginInitializerContext) {} - - public setup( - core: CoreSetup, - deps: AppPluginSetupDependencies - ): ApiKeyPluginSetup { - return {}; - } - - public start() {} - - public stop() {} -} diff --git a/x-pack/plugins/api_key/server/plugin.ts b/x-pack/plugins/api_key/server/plugin.ts deleted file mode 100644 index 0253a6b29a5ea..0000000000000 --- a/x-pack/plugins/api_key/server/plugin.ts +++ /dev/null @@ -1,34 +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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; -import { defineRoutes } from './routes'; - -export class ApiKeyPlugin - implements Plugin -{ - private readonly logger: Logger; - - constructor(initializerContext: PluginInitializerContext) { - this.logger = initializerContext.logger.get(); - } - - public setup(core: CoreSetup) { - this.logger.debug('apiKey plugin: Setup'); - const router = core.http.createRouter(); - - defineRoutes({ router, logger: this.logger, getStartServices: core.getStartServices }); - - return {}; - } - - public start(core: CoreStart) { - return {}; - } - - public stop() {} -} diff --git a/x-pack/plugins/search_api_keys/README.md b/x-pack/plugins/search_api_keys/README.md new file mode 100644 index 0000000000000..0b90c191667cc --- /dev/null +++ b/x-pack/plugins/search_api_keys/README.md @@ -0,0 +1,3 @@ +# Search API Keys + +The Search API Keys plugin is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. \ No newline at end of file diff --git a/x-pack/plugins/api_key/common/index.ts b/x-pack/plugins/search_api_keys/common/index.ts similarity index 77% rename from x-pack/plugins/api_key/common/index.ts rename to x-pack/plugins/search_api_keys/common/index.ts index 3540929f65d63..2906b1a96846a 100644 --- a/x-pack/plugins/api_key/common/index.ts +++ b/x-pack/plugins/search_api_keys/common/index.ts @@ -5,6 +5,6 @@ * 2.0. */ -export const PLUGIN_ID = 'apiKey'; -export const PLUGIN_NAME = 'ApiKey'; +export const PLUGIN_ID = 'searchApiKeys'; +export const PLUGIN_NAME = 'searchApiKeys'; export const PLUGIN_PATH = '/app/api_key'; diff --git a/x-pack/plugins/search_api_keys/common/types.ts b/x-pack/plugins/search_api_keys/common/types.ts new file mode 100644 index 0000000000000..111b9a4a91d40 --- /dev/null +++ b/x-pack/plugins/search_api_keys/common/types.ts @@ -0,0 +1,13 @@ +/* + * 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 interface UserStartPrivilegesResponse { + privileges: { + canCreateApiKeys: boolean; + canCreateIndex: boolean; + }; +} diff --git a/x-pack/plugins/api_key/jest.config.js b/x-pack/plugins/search_api_keys/jest.config.js similarity index 100% rename from x-pack/plugins/api_key/jest.config.js rename to x-pack/plugins/search_api_keys/jest.config.js diff --git a/x-pack/plugins/api_key/kibana.jsonc b/x-pack/plugins/search_api_keys/kibana.jsonc similarity index 53% rename from x-pack/plugins/api_key/kibana.jsonc rename to x-pack/plugins/search_api_keys/kibana.jsonc index 9b09493a8f77e..d720ffeab6faf 100644 --- a/x-pack/plugins/api_key/kibana.jsonc +++ b/x-pack/plugins/search_api_keys/kibana.jsonc @@ -1,19 +1,16 @@ { "type": "plugin", - "id": "@kbn/api-key", + "id": "@kbn/search-api-keys", "owner": "@elastic/search-kibana", "plugin": { - "id": "apiKey", + "id": "searchApiKeys", "server": true, "browser": true, "configPath": [ "xpack" ], - "requiredPlugins": [ - ], - "optionalPlugins": [ - ], - "requiredBundles": [ - ] + "requiredPlugins": [], + "optionalPlugins": [], + "requiredBundles": [] } -} +} \ No newline at end of file diff --git a/x-pack/plugins/api_key/public/index.ts b/x-pack/plugins/search_api_keys/public/index.ts similarity index 100% rename from x-pack/plugins/api_key/public/index.ts rename to x-pack/plugins/search_api_keys/public/index.ts diff --git a/x-pack/plugins/search_api_keys/public/plugin.ts b/x-pack/plugins/search_api_keys/public/plugin.ts new file mode 100644 index 0000000000000..e4f9e2406cb15 --- /dev/null +++ b/x-pack/plugins/search_api_keys/public/plugin.ts @@ -0,0 +1,23 @@ +/* + * 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 type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import type { SearchIndicesPluginSetup, SearchIndicesPluginStart } from './types'; + +export class SearchIndicesPlugin + implements Plugin +{ + public setup(core: CoreSetup): SearchIndicesPluginSetup { + return {}; + } + + public start(core: CoreStart): SearchIndicesPluginStart { + return {}; + } + + public stop() {} +} \ No newline at end of file diff --git a/x-pack/plugins/api_key/public/use_api_key.ts b/x-pack/plugins/search_api_keys/public/use_api_key.ts similarity index 100% rename from x-pack/plugins/api_key/public/use_api_key.ts rename to x-pack/plugins/search_api_keys/public/use_api_key.ts diff --git a/x-pack/plugins/search_api_keys/server/config.ts b/x-pack/plugins/search_api_keys/server/config.ts new file mode 100644 index 0000000000000..d6aaa87f69d2c --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/config.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 { schema, TypeOf } from '@kbn/config-schema'; +// import { PluginConfigDescriptor } from '@kbn/core/server'; + +// const configSchema = schema.object({ +// enabled: schema.boolean({ defaultValue: false }), +// }); + +// export type SearchApiKeysConfig = TypeOf; + +// export const config: PluginConfigDescriptor = { +// schema: configSchema, +// }; \ No newline at end of file diff --git a/x-pack/plugins/api_key/server/index.ts b/x-pack/plugins/search_api_keys/server/index.ts similarity index 72% rename from x-pack/plugins/api_key/server/index.ts rename to x-pack/plugins/search_api_keys/server/index.ts index 0e8b60d0def85..d2d6cc83ba9d9 100644 --- a/x-pack/plugins/api_key/server/index.ts +++ b/x-pack/plugins/search_api_keys/server/index.ts @@ -7,9 +7,9 @@ import { PluginInitializerContext } from '@kbn/core/server'; -export { config } from './config'; +// export { config } from './config'; export async function plugin(initializerContext: PluginInitializerContext) { - const { ApiKeyPlugin } = await import('./plugin'); - return new ApiKeyPlugin(initializerContext); + const { SearchApiKeysPlugin } = await import('./plugin'); + return new SearchApiKeysPlugin(initializerContext); } diff --git a/x-pack/plugins/search_api_keys/server/lib/privileges.ts b/x-pack/plugins/search_api_keys/server/lib/privileges.ts new file mode 100644 index 0000000000000..fcbb98ce888c4 --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/lib/privileges.ts @@ -0,0 +1,45 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { Logger } from '@kbn/logging'; + +import type { UserStartPrivilegesResponse } from '../../common/types'; + +export async function fetchUserStartPrivileges( + client: ElasticsearchClient, + logger: Logger, + indexName: string = 'test-index-name' +): Promise { + try { + const securityCheck = await client.security.hasPrivileges({ + cluster: ['manage_api_key'], + index: [ + { + names: [indexName], + privileges: ['create_index'], + }, + ], + }); + + return { + privileges: { + canCreateIndex: securityCheck?.index?.[indexName]?.create_index ?? false, + canCreateApiKeys: securityCheck?.cluster?.manage_api_key ?? false, + }, + }; + } catch (e) { + logger.error(`Error checking user privileges for searchIndices elasticsearch start`); + logger.error(e); + return { + privileges: { + canCreateIndex: false, + canCreateApiKeys: false, + }, + }; + } +} diff --git a/x-pack/plugins/search_api_keys/server/plugin.ts b/x-pack/plugins/search_api_keys/server/plugin.ts new file mode 100644 index 0000000000000..0f0c12ba36d00 --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/plugin.ts @@ -0,0 +1,45 @@ +/* + * 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 type { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '@kbn/core/server'; + +import type { SearchApiKeysPluginSetup, SearchApiKeysPluginStart } from './types'; +import { registerRoutes } from './routes/routes'; + +export class SearchApiKeysPlugin + implements Plugin +{ + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('searchApiKeys: Setup'); + this.logger.info('searchApiKeys test'); + const router = core.http.createRouter(); + + // Register server side APIs + registerRoutes(router, this.logger); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('searchApiKeys: Started'); + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts new file mode 100644 index 0000000000000..dec4093e8aea2 --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -0,0 +1,33 @@ +/* + * 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 type { IRouter } from '@kbn/core/server'; +import type { Logger } from '@kbn/logging'; + +import { fetchUserStartPrivileges } from '../lib/privileges'; + +export function registerRoutes(router: IRouter, logger: Logger) { + router.get( + { + path: '/internal/search_api_keys/start_privileges', + validate: {}, + options: { + access: 'internal', + }, + }, + async (context, _request, response) => { + const core = await context.core; + const client = core.elasticsearch.client.asCurrentUser; + const body = await fetchUserStartPrivileges(client, logger); + + return response.ok({ + body, + headers: { 'content-type': 'application/json' }, + }); + } + ); +} diff --git a/x-pack/plugins/search_api_keys/server/types.ts b/x-pack/plugins/search_api_keys/server/types.ts new file mode 100644 index 0000000000000..31e44cd9e56ab --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/types.ts @@ -0,0 +1,17 @@ +/* + * 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 type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SearchApiKeysPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SearchApiKeysPluginStart {} + +export interface AppPluginStartDependencies { + navigation: NavigationPublicPluginStart; +} diff --git a/x-pack/plugins/api_key/tsconfig.json b/x-pack/plugins/search_api_keys/tsconfig.json similarity index 100% rename from x-pack/plugins/api_key/tsconfig.json rename to x-pack/plugins/search_api_keys/tsconfig.json diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index a326956635d80..3dc637f8583ab 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -38,4 +38,4 @@ "kibanaReact" ] } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 534a64c74dd04..3aa88be2006fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6198,6 +6198,10 @@ version "0.0.0" uid "" +"@kbn/search-api-keys@link:x-pack/plugins/search_api_keys": + version "0.0.0" + uid "" + "@kbn/search-api-panels@link:packages/kbn-search-api-panels": version "0.0.0" uid "" From b1a83567ef56231187f48de55daf33a6d79f71c6 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 2 Sep 2024 20:39:19 +0100 Subject: [PATCH 03/36] api keys plugin working --- x-pack/.i18nrc.json | 2 +- x-pack/plugins/search_api_keys/common/types.ts | 1 - x-pack/plugins/search_api_keys/kibana.jsonc | 9 +++++++-- x-pack/plugins/search_api_keys/public/index.ts | 4 ++-- x-pack/plugins/search_api_keys/public/plugin.ts | 10 +++++----- x-pack/plugins/search_api_keys/public/types.ts | 17 +++++++++++++++++ .../search_api_keys/server/lib/privileges.ts | 11 +---------- .../search_api_keys/server/routes/routes.ts | 14 +++++++++----- x-pack/plugins/serverless_search/kibana.jsonc | 3 ++- 9 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 x-pack/plugins/search_api_keys/public/types.ts diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 0c37533d79d03..05506c311316b 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -101,9 +101,9 @@ "xpack.rollupJobs": ["packages/rollup", "plugins/rollup"], "xpack.runtimeFields": "plugins/runtime_fields", "xpack.screenshotting": "plugins/screenshotting", - "xpack.searchApiKeys": "plugins/search_api_keys", "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchIndices": "plugins/search_indices", + "xpack.searchApiKeys": "plugins/search_api_keys", "xpack.searchNotebooks": "plugins/search_notebooks", "xpack.searchPlayground": "plugins/search_playground", "xpack.searchInferenceEndpoints": "plugins/search_inference_endpoints", diff --git a/x-pack/plugins/search_api_keys/common/types.ts b/x-pack/plugins/search_api_keys/common/types.ts index 111b9a4a91d40..fae7dc4ce8102 100644 --- a/x-pack/plugins/search_api_keys/common/types.ts +++ b/x-pack/plugins/search_api_keys/common/types.ts @@ -8,6 +8,5 @@ export interface UserStartPrivilegesResponse { privileges: { canCreateApiKeys: boolean; - canCreateIndex: boolean; }; } diff --git a/x-pack/plugins/search_api_keys/kibana.jsonc b/x-pack/plugins/search_api_keys/kibana.jsonc index d720ffeab6faf..172d0fd5cf9ab 100644 --- a/x-pack/plugins/search_api_keys/kibana.jsonc +++ b/x-pack/plugins/search_api_keys/kibana.jsonc @@ -7,10 +7,15 @@ "server": true, "browser": true, "configPath": [ - "xpack" + "xpack", + "searchApiKeys" ], "requiredPlugins": [], - "optionalPlugins": [], + "optionalPlugins": [ + "cloud", + "console", + "usageCollection", + ], "requiredBundles": [] } } \ No newline at end of file diff --git a/x-pack/plugins/search_api_keys/public/index.ts b/x-pack/plugins/search_api_keys/public/index.ts index 7ae4e8e376a49..c75282b92b9b5 100644 --- a/x-pack/plugins/search_api_keys/public/index.ts +++ b/x-pack/plugins/search_api_keys/public/index.ts @@ -7,8 +7,8 @@ import { PluginInitializerContext } from '@kbn/core/public'; -import { ApiKeyPlugin } from './plugin'; +import { SearchApiKeysPlugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { - return new ApiKeyPlugin(initializerContext); + return new SearchApiKeysPlugin(); } diff --git a/x-pack/plugins/search_api_keys/public/plugin.ts b/x-pack/plugins/search_api_keys/public/plugin.ts index e4f9e2406cb15..9188c9fda614e 100644 --- a/x-pack/plugins/search_api_keys/public/plugin.ts +++ b/x-pack/plugins/search_api_keys/public/plugin.ts @@ -6,16 +6,16 @@ */ import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; -import type { SearchIndicesPluginSetup, SearchIndicesPluginStart } from './types'; +import type { SearchApiKeysPluginSetup, SearchApiKeysPluginStart } from './types'; -export class SearchIndicesPlugin - implements Plugin +export class SearchApiKeysPlugin + implements Plugin { - public setup(core: CoreSetup): SearchIndicesPluginSetup { + public setup(core: CoreSetup): SearchApiKeysPluginSetup { return {}; } - public start(core: CoreStart): SearchIndicesPluginStart { + public start(core: CoreStart): SearchApiKeysPluginStart { return {}; } diff --git a/x-pack/plugins/search_api_keys/public/types.ts b/x-pack/plugins/search_api_keys/public/types.ts new file mode 100644 index 0000000000000..9658ff3dc0173 --- /dev/null +++ b/x-pack/plugins/search_api_keys/public/types.ts @@ -0,0 +1,17 @@ +/* + * 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 type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SearchApiKeysPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SearchApiKeysPluginStart {} + +export interface AppPluginStartDependencies { + navigation: NavigationPublicPluginStart; +} \ No newline at end of file diff --git a/x-pack/plugins/search_api_keys/server/lib/privileges.ts b/x-pack/plugins/search_api_keys/server/lib/privileges.ts index fcbb98ce888c4..fe9e3b5edd43b 100644 --- a/x-pack/plugins/search_api_keys/server/lib/privileges.ts +++ b/x-pack/plugins/search_api_keys/server/lib/privileges.ts @@ -12,23 +12,15 @@ import type { UserStartPrivilegesResponse } from '../../common/types'; export async function fetchUserStartPrivileges( client: ElasticsearchClient, - logger: Logger, - indexName: string = 'test-index-name' + logger: Logger ): Promise { try { const securityCheck = await client.security.hasPrivileges({ cluster: ['manage_api_key'], - index: [ - { - names: [indexName], - privileges: ['create_index'], - }, - ], }); return { privileges: { - canCreateIndex: securityCheck?.index?.[indexName]?.create_index ?? false, canCreateApiKeys: securityCheck?.cluster?.manage_api_key ?? false, }, }; @@ -37,7 +29,6 @@ export async function fetchUserStartPrivileges( logger.error(e); return { privileges: { - canCreateIndex: false, canCreateApiKeys: false, }, }; diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts index dec4093e8aea2..f76006ad0ac25 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -13,7 +13,7 @@ import { fetchUserStartPrivileges } from '../lib/privileges'; export function registerRoutes(router: IRouter, logger: Logger) { router.get( { - path: '/internal/search_api_keys/start_privileges', + path: '/internal/search_api_keys/create', validate: {}, options: { access: 'internal', @@ -24,10 +24,14 @@ export function registerRoutes(router: IRouter, logger: Logger) { const client = core.elasticsearch.client.asCurrentUser; const body = await fetchUserStartPrivileges(client, logger); - return response.ok({ - body, - headers: { 'content-type': 'application/json' }, - }); + if (body.privileges.canCreateApiKeys) { + return response.ok({ + body: { apiKey: '123456789' }, + headers: { 'content-type': 'application/json' }, + }); + } else { + throw new Error('Unauthorized'); + } } ); } diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index 3dc637f8583ab..2c5dd0b1b771d 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -32,7 +32,8 @@ "searchHomepage", "searchIndices", "searchInferenceEndpoints", - "usageCollection" + "usageCollection", + "searchApiKeys" ], "requiredBundles": [ "kibanaReact" From df937a120d9f5254a6c67a75b0112b835fdd147b Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 2 Sep 2024 20:39:39 +0100 Subject: [PATCH 04/36] WIP --- x-pack/plugins/search_api_keys/public/plugin.ts | 2 +- x-pack/plugins/search_api_keys/public/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/search_api_keys/public/plugin.ts b/x-pack/plugins/search_api_keys/public/plugin.ts index 9188c9fda614e..1cca9ae1b2ba7 100644 --- a/x-pack/plugins/search_api_keys/public/plugin.ts +++ b/x-pack/plugins/search_api_keys/public/plugin.ts @@ -20,4 +20,4 @@ export class SearchApiKeysPlugin } public stop() {} -} \ No newline at end of file +} diff --git a/x-pack/plugins/search_api_keys/public/types.ts b/x-pack/plugins/search_api_keys/public/types.ts index 9658ff3dc0173..31e44cd9e56ab 100644 --- a/x-pack/plugins/search_api_keys/public/types.ts +++ b/x-pack/plugins/search_api_keys/public/types.ts @@ -14,4 +14,4 @@ export interface SearchApiKeysPluginStart {} export interface AppPluginStartDependencies { navigation: NavigationPublicPluginStart; -} \ No newline at end of file +} From 67b836473ca8f921d77bcac7446e466d8ef179c1 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Tue, 3 Sep 2024 11:06:04 +0100 Subject: [PATCH 05/36] implement API for API Key generation --- .../plugins/search_api_keys/common/types.ts | 9 ++-- .../search_api_keys/server/lib/create_key.ts | 29 ++++++++++++ .../search_api_keys/server/lib/privileges.ts | 38 ++++++++++------ .../search_api_keys/server/routes/routes.ts | 44 +++++++++++++++---- .../search_playground/server/routes.ts | 38 ---------------- 5 files changed, 93 insertions(+), 65 deletions(-) create mode 100644 x-pack/plugins/search_api_keys/server/lib/create_key.ts diff --git a/x-pack/plugins/search_api_keys/common/types.ts b/x-pack/plugins/search_api_keys/common/types.ts index fae7dc4ce8102..13f4c4ec2ad3b 100644 --- a/x-pack/plugins/search_api_keys/common/types.ts +++ b/x-pack/plugins/search_api_keys/common/types.ts @@ -5,8 +5,9 @@ * 2.0. */ -export interface UserStartPrivilegesResponse { - privileges: { - canCreateApiKeys: boolean; - }; +export interface APIKeyCreationResponse { + api_key: string; + encoded: string; + name: string; + expiration?: number; } diff --git a/x-pack/plugins/search_api_keys/server/lib/create_key.ts b/x-pack/plugins/search_api_keys/server/lib/create_key.ts new file mode 100644 index 0000000000000..e4d57cd3aa8f4 --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/lib/create_key.ts @@ -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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { Logger } from '@kbn/logging'; +import { APIKeyCreationResponse } from '../../common/types'; + +export async function createAPIKey( + name: string, + client: ElasticsearchClient, + logger: Logger +): Promise { + try { + const apiKey = await client.security.createApiKey({ + name, + role_descriptors: {}, + }); + + return apiKey; + } catch (e) { + logger.error(`Error creating API Key for elasticsearch start`); + logger.error(e); + throw e; + } +} diff --git a/x-pack/plugins/search_api_keys/server/lib/privileges.ts b/x-pack/plugins/search_api_keys/server/lib/privileges.ts index fe9e3b5edd43b..c788bc27c9cf0 100644 --- a/x-pack/plugins/search_api_keys/server/lib/privileges.ts +++ b/x-pack/plugins/search_api_keys/server/lib/privileges.ts @@ -8,29 +8,39 @@ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; -import type { UserStartPrivilegesResponse } from '../../common/types'; - export async function fetchUserStartPrivileges( client: ElasticsearchClient, logger: Logger -): Promise { +): Promise { try { const securityCheck = await client.security.hasPrivileges({ - cluster: ['manage_api_key'], + cluster: ['manage_own_api_key'], }); - return { - privileges: { - canCreateApiKeys: securityCheck?.cluster?.manage_api_key ?? false, - }, - }; + return securityCheck?.cluster?.manage_own_api_key ?? false; } catch (e) { - logger.error(`Error checking user privileges for searchIndices elasticsearch start`); + logger.error(`Error checking user privileges for search API Keys`); logger.error(e); - return { - privileges: { - canCreateApiKeys: false, + return false; + } +} + +export async function fetchClusterHasApiKeys( + client: ElasticsearchClient, + logger: Logger +): Promise { + try { + const clusterApiKeys = await client.security.queryApiKeys({ + query: { + term: { + invalidated: false, + }, }, - }; + }); + return clusterApiKeys.api_keys.length > 0; + } catch (e) { + logger.error(`Error checking cluster for existing valid API keys`); + logger.error(e); + return true; } } diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts index f76006ad0ac25..69c1baf5410b6 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -8,29 +8,55 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; -import { fetchUserStartPrivileges } from '../lib/privileges'; +import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; +import { createAPIKey } from '../lib/create_key'; + +const BASE_PATH = '/internal/search_api_keys'; export function registerRoutes(router: IRouter, logger: Logger) { router.get( { - path: '/internal/search_api_keys/create', + path: `${BASE_PATH}/create`, validate: {}, options: { access: 'internal', }, }, async (context, _request, response) => { - const core = await context.core; - const client = core.elasticsearch.client.asCurrentUser; - const body = await fetchUserStartPrivileges(client, logger); + try { + const core = await context.core; + const client = core.elasticsearch.client.asCurrentUser; + const clusterHasApiKeys = await fetchClusterHasApiKeys(client, logger); + + if (clusterHasApiKeys) { + return response.customError({ + body: { message: 'Project already has API keys' }, + statusCode: 400, + }); + } + + const canCreateApiKeys = await fetchUserStartPrivileges(client, logger); + + if (!canCreateApiKeys) { + return response.customError({ + body: { message: 'User does not have required privileges' }, + statusCode: 403, + }); + } + + const apiKey = await createAPIKey('Onboarding API Key', client, logger); - if (body.privileges.canCreateApiKeys) { return response.ok({ - body: { apiKey: '123456789' }, + body: apiKey, headers: { 'content-type': 'application/json' }, }); - } else { - throw new Error('Unauthorized'); + } catch (e) { + logger.error(`Error creating API Key`); + logger.error(e); + return response.customError({ + body: { message: e.message }, + statusCode: 500, + }); } } ); diff --git a/x-pack/plugins/search_playground/server/routes.ts b/x-pack/plugins/search_playground/server/routes.ts index 8d7769020f445..2a8e723b790a7 100644 --- a/x-pack/plugins/search_playground/server/routes.ts +++ b/x-pack/plugins/search_playground/server/routes.ts @@ -172,44 +172,6 @@ export function defineRoutes({ }) ); - router.post( - { - path: APIRoutes.POST_API_KEY, - validate: { - body: schema.object({ - name: schema.string(), - expiresInDays: schema.number(), - indices: schema.arrayOf(schema.string()), - }), - }, - }, - errorHandler(logger)(async (context, request, response) => { - const { name, expiresInDays, indices } = request.body; - const { client } = (await context.core).elasticsearch; - - const apiKey = await client.asCurrentUser.security.createApiKey({ - name, - expiration: `${expiresInDays}d`, - role_descriptors: { - [`playground-${name}-role`]: { - cluster: [], - indices: [ - { - names: indices, - privileges: ['read'], - }, - ], - }, - }, - }); - - return response.ok({ - body: { apiKey }, - headers: { 'content-type': 'application/json' }, - }); - }) - ); - // SECURITY: We don't apply any authorization tags to this route because all actions performed // on behalf of the user making the request and governed by the user's own cluster privileges. router.get( From 245d4cbdba2d1621c870fa18789147bfec491b23 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Tue, 3 Sep 2024 12:49:51 +0100 Subject: [PATCH 06/36] fix privilege --- x-pack/plugins/search_api_keys/server/lib/privileges.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/search_api_keys/server/lib/privileges.ts b/x-pack/plugins/search_api_keys/server/lib/privileges.ts index c788bc27c9cf0..d956e1d74e873 100644 --- a/x-pack/plugins/search_api_keys/server/lib/privileges.ts +++ b/x-pack/plugins/search_api_keys/server/lib/privileges.ts @@ -13,11 +13,13 @@ export async function fetchUserStartPrivileges( logger: Logger ): Promise { try { + // relying on manage cluster privilege to check if user can create API keys + // and can also have permissions for index monitoring const securityCheck = await client.security.hasPrivileges({ - cluster: ['manage_own_api_key'], + cluster: ['manage'], }); - return securityCheck?.cluster?.manage_own_api_key ?? false; + return securityCheck?.cluster?.manage ?? false; } catch (e) { logger.error(`Error checking user privileges for search API Keys`); logger.error(e); From 25c326052f47c8d905309b0f0c6292705a02f39f Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Sun, 8 Sep 2024 23:27:20 +0200 Subject: [PATCH 07/36] Add get api route --- .../plugins/search_api_keys/common/types.ts | 14 ++++++ .../server/lib/get_key_by_id.ts | 28 +++++++++++ .../search_api_keys/server/routes/routes.ts | 49 +++++++++++++++++-- 3 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts diff --git a/x-pack/plugins/search_api_keys/common/types.ts b/x-pack/plugins/search_api_keys/common/types.ts index 13f4c4ec2ad3b..85f792773455e 100644 --- a/x-pack/plugins/search_api_keys/common/types.ts +++ b/x-pack/plugins/search_api_keys/common/types.ts @@ -5,9 +5,23 @@ * 2.0. */ +import { Id, long, Name } from '@elastic/elasticsearch/lib/api/types'; + +export enum APIRoutes { + API_KEYS = '/internal/search_api_keys', +} + export interface APIKeyCreationResponse { api_key: string; encoded: string; name: string; expiration?: number; } + +export interface GetApiKeyResponse { + creation?: long; + expiration?: long; + id: Id; + invalidated?: boolean; + name: Name; +} diff --git a/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts b/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts new file mode 100644 index 0000000000000..20cd6143c9999 --- /dev/null +++ b/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts @@ -0,0 +1,28 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { Logger } from '@kbn/logging'; +import { GetApiKeyResponse } from '../../common/types'; + +export async function getAPIKeyById( + id: string, + client: ElasticsearchClient, + logger: Logger +): Promise { + try { + const apiKey = await client.security.getApiKey({ + id, + }); + + return apiKey.api_keys?.[0]; + } catch (e) { + logger.error(`Error getting API Key for elasticsearch start`); + logger.error(e); + throw e; + } +} diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts index 69c1baf5410b6..f7697e7fec80b 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -8,15 +8,56 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; -import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; +import { schema } from '@kbn/config-schema'; +import { APIRoutes } from '../../common/types'; +import { getAPIKeyById } from '../lib/get_key_by_id'; import { createAPIKey } from '../lib/create_key'; - -const BASE_PATH = '/internal/search_api_keys'; +import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; export function registerRoutes(router: IRouter, logger: Logger) { router.get( { - path: `${BASE_PATH}/create`, + path: APIRoutes.API_KEYS, + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + options: { + access: 'internal', + }, + }, + async (context, request, response) => { + try { + const core = await context.core; + const client = core.elasticsearch.client.asCurrentUser; + const apiKey = await getAPIKeyById(request.params.id, client, logger); + + if (!apiKey || !apiKey.invalidated) { + return response.customError({ + body: { message: 'API key is expired or invalid.' }, + statusCode: 401, + }); + } + + return response.ok({ + body: apiKey, + headers: { 'content-type': 'application/json' }, + }); + } catch (e) { + logger.error(`Error fetching API Key`); + logger.error(e); + return response.customError({ + body: { message: e.message }, + statusCode: 500, + }); + } + } + ); + + router.post( + { + path: APIRoutes.API_KEYS, validate: {}, options: { access: 'internal', From e2024d7706aee111108889d1c3e0e2b5d62b878f Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 17 Sep 2024 01:30:22 +0200 Subject: [PATCH 08/36] Update validity route --- .../plugins/search_api_keys/common/types.ts | 20 ++++++++-------- .../components/api_key_flyout_wrapper.tsx | 0 .../public/components/api_key_form.tsx | 0 .../public/hooks/use_current_user.ts | 0 .../plugins/search_api_keys/public/plugin.ts | 23 ------------------- .../plugins/search_api_keys/public/types.ts | 17 -------------- .../search_api_keys/server/routes/routes.ts | 17 +++++++------- 7 files changed, 18 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx create mode 100644 x-pack/plugins/search_api_keys/public/components/api_key_form.tsx create mode 100644 x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts delete mode 100644 x-pack/plugins/search_api_keys/public/plugin.ts delete mode 100644 x-pack/plugins/search_api_keys/public/types.ts diff --git a/x-pack/plugins/search_api_keys/common/types.ts b/x-pack/plugins/search_api_keys/common/types.ts index 85f792773455e..b0efe74bbc0e7 100644 --- a/x-pack/plugins/search_api_keys/common/types.ts +++ b/x-pack/plugins/search_api_keys/common/types.ts @@ -5,23 +5,21 @@ * 2.0. */ -import { Id, long, Name } from '@elastic/elasticsearch/lib/api/types'; - export enum APIRoutes { API_KEYS = '/internal/search_api_keys', + API_KEY_VALIDITY = '/internal/search_api_keys/validity', } -export interface APIKeyCreationResponse { - api_key: string; - encoded: string; +export interface APIKey { + id: string; name: string; expiration?: number; + invalidated?: boolean; } -export interface GetApiKeyResponse { - creation?: long; - expiration?: long; - id: Id; - invalidated?: boolean; - name: Name; +export interface APIKeyCreationResponse extends Pick { + api_key: string; + encoded: string; } + +export type GetApiKeyResponse = APIKey; diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts b/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/search_api_keys/public/plugin.ts b/x-pack/plugins/search_api_keys/public/plugin.ts deleted file mode 100644 index 1cca9ae1b2ba7..0000000000000 --- a/x-pack/plugins/search_api_keys/public/plugin.ts +++ /dev/null @@ -1,23 +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 type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; -import type { SearchApiKeysPluginSetup, SearchApiKeysPluginStart } from './types'; - -export class SearchApiKeysPlugin - implements Plugin -{ - public setup(core: CoreSetup): SearchApiKeysPluginSetup { - return {}; - } - - public start(core: CoreStart): SearchApiKeysPluginStart { - return {}; - } - - public stop() {} -} diff --git a/x-pack/plugins/search_api_keys/public/types.ts b/x-pack/plugins/search_api_keys/public/types.ts deleted file mode 100644 index 31e44cd9e56ab..0000000000000 --- a/x-pack/plugins/search_api_keys/public/types.ts +++ /dev/null @@ -1,17 +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 type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SearchApiKeysPluginSetup {} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SearchApiKeysPluginStart {} - -export interface AppPluginStartDependencies { - navigation: NavigationPublicPluginStart; -} diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts index f7697e7fec80b..df8dee8099d27 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -15,11 +15,11 @@ import { createAPIKey } from '../lib/create_key'; import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; export function registerRoutes(router: IRouter, logger: Logger) { - router.get( + router.post( { - path: APIRoutes.API_KEYS, + path: APIRoutes.API_KEY_VALIDITY, validate: { - params: schema.object({ + body: schema.object({ id: schema.string(), }), }, @@ -31,17 +31,18 @@ export function registerRoutes(router: IRouter, logger: Logger) { try { const core = await context.core; const client = core.elasticsearch.client.asCurrentUser; - const apiKey = await getAPIKeyById(request.params.id, client, logger); + const apiKey = await getAPIKeyById(request.body.id, client, logger); + logger.info('API KEY' + JSON.stringify(apiKey)); - if (!apiKey || !apiKey.invalidated) { + if (!apiKey) { return response.customError({ - body: { message: 'API key is expired or invalid.' }, - statusCode: 401, + body: { message: 'API key is not found.' }, + statusCode: 404, }); } return response.ok({ - body: apiKey, + body: { isValid: !apiKey.invalidated }, headers: { 'content-type': 'application/json' }, }); } catch (e) { From 07c80e7eda1d888ec4265f503aa39c2c49c648d0 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 17 Sep 2024 01:32:13 +0200 Subject: [PATCH 09/36] Add apikeyfrom component and api search hook --- x-pack/plugins/search_api_keys/kibana.jsonc | 6 +- .../components/api_key_flyout_wrapper.tsx | 21 ++++ .../public/components/api_key_form.tsx | 84 +++++++++++++++ .../public/hooks/use_current_user.ts | 29 +++++ .../public/hooks/use_search_api_key.ts | 101 ++++++++++++++++++ .../plugins/search_api_keys/public/index.ts | 8 +- .../search_api_keys/public/use_api_key.ts | 57 ---------- x-pack/plugins/search_indices/kibana.jsonc | 1 + .../public/components/start/start_page.tsx | 2 + 9 files changed, 243 insertions(+), 66 deletions(-) create mode 100644 x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts delete mode 100644 x-pack/plugins/search_api_keys/public/use_api_key.ts diff --git a/x-pack/plugins/search_api_keys/kibana.jsonc b/x-pack/plugins/search_api_keys/kibana.jsonc index 172d0fd5cf9ab..2d95bcbe778ec 100644 --- a/x-pack/plugins/search_api_keys/kibana.jsonc +++ b/x-pack/plugins/search_api_keys/kibana.jsonc @@ -10,7 +10,9 @@ "xpack", "searchApiKeys" ], - "requiredPlugins": [], + "requiredPlugins": [ + "kibanaReact", + ], "optionalPlugins": [ "cloud", "console", @@ -18,4 +20,4 @@ ], "requiredBundles": [] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx index e69de29bb2d1d..20cfe5df7b5dc 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx @@ -0,0 +1,21 @@ +/* + * 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 { ApiKeyFlyout } from '@kbn/security-api-key-management'; +import React from 'react'; +import { useCurrentUser } from '../hooks/use_current_user'; + +interface ApiKeyFlyoutWrapperProps { + onClose: () => void; + onSuccess: (apiKey: { id: string; encoded: string }) => void; +} + +export const ApiKeyFlyoutWrapper: React.FC = ({ onClose, onSuccess }) => { + const user = useCurrentUser(); + + return ; +}; diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx index e69de29bb2d1d..6cae694196b97 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx @@ -0,0 +1,84 @@ +/* + * 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, { useCallback, useState } from 'react'; +import { + EuiButton, + EuiButtonIcon, + EuiCode, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { ApiKeyFlyoutWrapper } from './api_key_flyout_wrapper'; +import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; + +export const ApiKeyForm = () => { + const [showFlyout, setShowFlyout] = useState(false); + const { apiKey, isLoading, status, handleSaveKey } = useSearchApiKey(); + const handleAddToClipboard = useCallback( + () => apiKey && navigator.clipboard.writeText(apiKey), + [apiKey] + ); + + return ( + + + +
+ +
+
+
+ + {apiKey && ( + + + + {status === Status.showHiddenKey ? '•'.repeat(30) : apiKey} + + + {status === Status.showPreviewKey && ( + + + + )} + + )} + {status === Status.showCreateButton && ( + <> + setShowFlyout(true)} + > + + + {showFlyout && ( + setShowFlyout(false)} onSuccess={handleSaveKey} /> + )} + + )} + +
+ ); +}; diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts b/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts index e69de29bb2d1d..377d32ccc24b5 100644 --- a/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts +++ b/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts @@ -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 { useState, useEffect } from 'react'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { AuthenticatedUser } from '@kbn/core-security-common'; + +export const useCurrentUser = () => { + const { security } = useKibana().services; + const [user, setUser] = useState(undefined); + + useEffect(() => { + const getCurrentUser = async () => { + try { + const authenticatedUser = await security!.authc.getCurrentUser(); + setUser(authenticatedUser); + } catch { + setUser(undefined); + } + }; + getCurrentUser(); + }, [security]); + + return user; +}; diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts b/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts new file mode 100644 index 0000000000000..6c3e9339d340a --- /dev/null +++ b/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts @@ -0,0 +1,101 @@ +/* + * 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 { useState, useEffect, useCallback } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { APIKeyCreationResponse, APIRoutes } from '../../common/types'; + +const API_KEY_STORAGE_KEY = 'searchApiKey'; +export enum Status { + loading = 'loading', + showCreateButton = 'showCreateButton', + showHiddenKey = 'showHiddenKey', + showPreviewKey = 'showPreviewKey', +} + +export const useSearchApiKey = () => { + const { http } = useKibana().services; + const [apiKey, setApiKey] = useState(null); + const [status, setStatus] = useState(Status.loading); + const handleSaveKey = useCallback(({ id, encoded }: { id: string; encoded: string }) => { + sessionStorage.setItem(API_KEY_STORAGE_KEY, JSON.stringify({ id, encoded })); + setApiKey(encoded); + setStatus(Status.showPreviewKey); + }, []); + const { mutateAsync: validateApiKey } = useMutation(async (id: string) => { + try { + if (!http?.post) { + throw new Error('HTTP service is unavailable'); + } + + const response = await http.post<{ isValid: boolean }>(APIRoutes.API_KEY_VALIDITY, { + body: JSON.stringify({ id }), + }); + + return response.isValid; + } catch (err) { + return false; + } + }); + const { mutateAsync: createApiKey } = useMutation({ + mutationFn: async () => { + try { + if (!http?.post) { + throw new Error('HTTP service is unavailable'); + } + + return await http.post(APIRoutes.API_KEYS); + } catch (err) { + if (err.response?.status === 400) { + setStatus(Status.showCreateButton); + } else { + throw err; + } + } + }, + onSuccess: (receivedApiKey) => { + if (receivedApiKey) { + sessionStorage.setItem( + API_KEY_STORAGE_KEY, + JSON.stringify({ id: receivedApiKey.id, encoded: receivedApiKey.encoded }) + ); + setApiKey(receivedApiKey.encoded); + setStatus(Status.showHiddenKey); + } + }, + }); + + useEffect(() => { + (async () => { + try { + const storedKey = sessionStorage.getItem(API_KEY_STORAGE_KEY); + + if (storedKey) { + const { id, encoded } = JSON.parse(storedKey); + + if (await validateApiKey(id)) { + setApiKey(encoded); + setStatus(Status.showHiddenKey); + } else { + setApiKey(null); + sessionStorage.removeItem(API_KEY_STORAGE_KEY); + } + } else { + await createApiKey(); + } + } catch (e) { + throw e; + } + })(); + }, [validateApiKey, createApiKey]); + + return { + apiKey, + handleSaveKey, + status, + }; +}; diff --git a/x-pack/plugins/search_api_keys/public/index.ts b/x-pack/plugins/search_api_keys/public/index.ts index c75282b92b9b5..eee2948d3ec54 100644 --- a/x-pack/plugins/search_api_keys/public/index.ts +++ b/x-pack/plugins/search_api_keys/public/index.ts @@ -5,10 +5,4 @@ * 2.0. */ -import { PluginInitializerContext } from '@kbn/core/public'; - -import { SearchApiKeysPlugin } from './plugin'; - -export function plugin(initializerContext: PluginInitializerContext) { - return new SearchApiKeysPlugin(); -} +export { ApiKeyForm } from './components/api_key_form'; diff --git a/x-pack/plugins/search_api_keys/public/use_api_key.ts b/x-pack/plugins/search_api_keys/public/use_api_key.ts deleted file mode 100644 index f1b4c81939892..0000000000000 --- a/x-pack/plugins/search_api_keys/public/use_api_key.ts +++ /dev/null @@ -1,57 +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 { useState, useEffect } from 'react'; - -export const useApiKey = (key) => { - const [apiKey, setApiKey] = useState(null); - const [isKeyLoaded, setIsKeyLoaded] = useState(false); - - useEffect(() => { - const storedKey = sessionStorage.getItem(key); - if (storedKey) { - setApiKey(storedKey); - setIsKeyLoaded(true); - } - }, [key]); - - const fetchApiKey = async () => { - const response = await fetch('/api/generate-key', { - method: 'POST', - body: JSON.stringify({ key }), - }); - const data = await response.json(); - return data.apiKey; - }; - - const resetKey = () => { - sessionStorage.removeItem(key); - setApiKey(null); - refetch(); - }; - - const createApiKey = async (newKeyData) => { - if (!apiKey) return; - const response = await fetch('/api/create-key', { - method: 'POST', - body: JSON.stringify({ key, ...newKeyData }), - }); - const data = await response.json(); - - return data; - }; - - const getApiKeyPreview = () => { - return apiKey ? `${apiKey.slice(0, 10)}**********` : ''; - }; - - return { - apiKey, - resetKey, - getApiKeyPreview, - createApiKey, - }; -}; diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc index 7f23aa80fef15..e23bc7ba78d5f 100644 --- a/x-pack/plugins/search_indices/kibana.jsonc +++ b/x-pack/plugins/search_indices/kibana.jsonc @@ -12,6 +12,7 @@ ], "requiredPlugins": [ "share", + "searchApiKeys", ], "optionalPlugins": [ "cloud", diff --git a/x-pack/plugins/search_indices/public/components/start/start_page.tsx b/x-pack/plugins/search_indices/public/components/start/start_page.tsx index 0982a67843cce..56386202e937a 100644 --- a/x-pack/plugins/search_indices/public/components/start/start_page.tsx +++ b/x-pack/plugins/search_indices/public/components/start/start_page.tsx @@ -10,6 +10,7 @@ import React, { useMemo } from 'react'; import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; +import { ApiKeyForm } from '@kbn/search-api-keys/public'; import { useKibana } from '../../hooks/use_kibana'; export const ElasticsearchStartPage = () => { @@ -29,6 +30,7 @@ export const ElasticsearchStartPage = () => { > + {embeddableConsole} From 9734255a366dbb85cc7c4458a56d6f098c676b41 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 17 Sep 2024 02:00:08 +0200 Subject: [PATCH 10/36] Use dispatch for state and apiKey --- .../public/hooks/use_search_api_key.ts | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts b/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts index 6c3e9339d340a..6fe6f91565b22 100644 --- a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts +++ b/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts @@ -4,12 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useState, useEffect, useCallback } from 'react'; +import { useEffect, useCallback, useReducer } from 'react'; import { useMutation } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { APIKeyCreationResponse, APIRoutes } from '../../common/types'; const API_KEY_STORAGE_KEY = 'searchApiKey'; + export enum Status { loading = 'loading', showCreateButton = 'showCreateButton', @@ -17,14 +18,40 @@ export enum Status { showPreviewKey = 'showPreviewKey', } +interface ApiKeyState { + status: Status; + apiKey: string | null; +} + +type Action = + | { type: 'SET_API_KEY'; apiKey: string; status: Status } + | { type: 'SET_STATUS'; status: Status } + | { type: 'CLEAR_API_KEY' }; + +const initialState: ApiKeyState = { + apiKey: null, + status: Status.loading, +}; + +const reducer = (state: ApiKeyState, action: Action): ApiKeyState => { + switch (action.type) { + case 'SET_API_KEY': + return { ...state, apiKey: action.apiKey, status: action.status }; + case 'SET_STATUS': + return { ...state, status: action.status }; + case 'CLEAR_API_KEY': + return { ...state, apiKey: null, status: Status.showCreateButton }; + default: + return state; + } +}; + export const useSearchApiKey = () => { const { http } = useKibana().services; - const [apiKey, setApiKey] = useState(null); - const [status, setStatus] = useState(Status.loading); + const [state, dispatch] = useReducer(reducer, initialState); const handleSaveKey = useCallback(({ id, encoded }: { id: string; encoded: string }) => { sessionStorage.setItem(API_KEY_STORAGE_KEY, JSON.stringify({ id, encoded })); - setApiKey(encoded); - setStatus(Status.showPreviewKey); + dispatch({ type: 'SET_API_KEY', apiKey: encoded, status: Status.showPreviewKey }); }, []); const { mutateAsync: validateApiKey } = useMutation(async (id: string) => { try { @@ -51,7 +78,7 @@ export const useSearchApiKey = () => { return await http.post(APIRoutes.API_KEYS); } catch (err) { if (err.response?.status === 400) { - setStatus(Status.showCreateButton); + dispatch({ type: 'SET_STATUS', status: Status.showCreateButton }); } else { throw err; } @@ -63,8 +90,11 @@ export const useSearchApiKey = () => { API_KEY_STORAGE_KEY, JSON.stringify({ id: receivedApiKey.id, encoded: receivedApiKey.encoded }) ); - setApiKey(receivedApiKey.encoded); - setStatus(Status.showHiddenKey); + dispatch({ + type: 'SET_API_KEY', + apiKey: receivedApiKey.encoded, + status: Status.showHiddenKey, + }); } }, }); @@ -78,11 +108,16 @@ export const useSearchApiKey = () => { const { id, encoded } = JSON.parse(storedKey); if (await validateApiKey(id)) { - setApiKey(encoded); - setStatus(Status.showHiddenKey); + dispatch({ + type: 'SET_API_KEY', + apiKey: encoded, + status: Status.showHiddenKey, + }); } else { - setApiKey(null); sessionStorage.removeItem(API_KEY_STORAGE_KEY); + dispatch({ + type: 'CLEAR_API_KEY', + }); } } else { await createApiKey(); @@ -94,8 +129,8 @@ export const useSearchApiKey = () => { }, [validateApiKey, createApiKey]); return { - apiKey, + apiKey: state.apiKey, handleSaveKey, - status, + status: state.status, }; }; From 703261ccb2c56642d1ab6a759e2802f0bef10f3d Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 17 Sep 2024 02:27:02 +0200 Subject: [PATCH 11/36] Use plugin --- .../public/components/api_key_form.tsx | 91 +++++++++---------- .../plugins/search_api_keys/public/index.ts | 5 + .../plugins/search_api_keys/public/plugin.ts | 20 ++++ .../components/indices/details_page.tsx | 9 +- 4 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 x-pack/plugins/search_api_keys/public/plugin.ts diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx index 6cae694196b97..f01e7e31c1431 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx @@ -13,6 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiTitle, + useEuiTheme, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -20,65 +21,63 @@ import { ApiKeyFlyoutWrapper } from './api_key_flyout_wrapper'; import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; export const ApiKeyForm = () => { + const { euiTheme } = useEuiTheme(); const [showFlyout, setShowFlyout] = useState(false); - const { apiKey, isLoading, status, handleSaveKey } = useSearchApiKey(); + const { apiKey, status, handleSaveKey } = useSearchApiKey(); const handleAddToClipboard = useCallback( () => apiKey && navigator.clipboard.writeText(apiKey), [apiKey] ); return ( - - - + + +
- - {apiKey && ( - - - - {status === Status.showHiddenKey ? '•'.repeat(30) : apiKey} - - - {status === Status.showPreviewKey && ( - - - - )} - - )} - {status === Status.showCreateButton && ( - <> - setShowFlyout(true)} - > - + + + {status === Status.showHiddenKey ? '•'.repeat(30) : apiKey} + + + {status === Status.showPreviewKey && ( + + - - {showFlyout && ( - setShowFlyout(false)} onSuccess={handleSaveKey} /> - )} - - )} - +
+ )} + + )} + {status === Status.showCreateButton && ( + + setShowFlyout(true)} + > + + + {showFlyout && ( + setShowFlyout(false)} onSuccess={handleSaveKey} /> + )} + + )}
); }; diff --git a/x-pack/plugins/search_api_keys/public/index.ts b/x-pack/plugins/search_api_keys/public/index.ts index eee2948d3ec54..5c4f6e5773e40 100644 --- a/x-pack/plugins/search_api_keys/public/index.ts +++ b/x-pack/plugins/search_api_keys/public/index.ts @@ -4,5 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { SearchApiKeysPlugin } from './plugin'; export { ApiKeyForm } from './components/api_key_form'; + +export function plugin() { + return new SearchApiKeysPlugin(); +} diff --git a/x-pack/plugins/search_api_keys/public/plugin.ts b/x-pack/plugins/search_api_keys/public/plugin.ts new file mode 100644 index 0000000000000..458b8b42c05d3 --- /dev/null +++ b/x-pack/plugins/search_api_keys/public/plugin.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 type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; + +export class SearchApiKeysPlugin implements Plugin<{}, {}> { + public setup(core: CoreSetup): {} { + return {}; + } + + public start(core: CoreStart): {} { + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx index 85021e79edbf2..cb648feeba433 100644 --- a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx @@ -25,6 +25,7 @@ import { useParams } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; +import { ApiKeyForm } from '@kbn/search-api-keys/public'; import { useIndex } from '../../hooks/api/use_index'; import { useKibana } from '../../hooks/use_kibana'; import { ConnectionDetails } from '../connection_details/connection_details'; @@ -167,11 +168,13 @@ export const SearchIndexDetailsPage = () => { /> )} - - + + - {/* TODO: API KEY */} + + + From 53f626303599d9fff5a2769661efac25de4dba93 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 23 Sep 2024 13:40:20 +0200 Subject: [PATCH 12/36] Fix PR comments --- x-pack/plugins/search_api_keys/jest.config.js | 6 +++--- .../public/components/api_key_form.tsx | 10 ++++++---- .../plugins/search_api_keys/server/config.ts | 19 ------------------- .../search_api_keys/server/lib/create_key.ts | 2 +- .../server/lib/get_key_by_id.ts | 2 +- .../plugins/search_api_keys/server/plugin.ts | 1 - .../search_api_keys/server/routes/routes.ts | 1 - x-pack/plugins/search_indices/kibana.jsonc | 2 +- x-pack/plugins/serverless_search/kibana.jsonc | 5 ++--- 9 files changed, 14 insertions(+), 34 deletions(-) delete mode 100644 x-pack/plugins/search_api_keys/server/config.ts diff --git a/x-pack/plugins/search_api_keys/jest.config.js b/x-pack/plugins/search_api_keys/jest.config.js index d23d0d55128b5..288bf405db513 100644 --- a/x-pack/plugins/search_api_keys/jest.config.js +++ b/x-pack/plugins/search_api_keys/jest.config.js @@ -8,8 +8,8 @@ module.exports = { preset: '@kbn/test', rootDir: '../../..', - roots: ['/x-pack/plugins/search_playground'], - coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_playground', + roots: ['/x-pack/plugins/search_api_keys'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_api_keys', coverageReporters: ['text', 'html'], - collectCoverageFrom: ['/x-pack/plugins/search_playground/{public,server}/**/*.{ts,tsx}'], + collectCoverageFrom: ['/x-pack/plugins/search_api_keys/{public,server}/**/*.{ts,tsx}'], }; diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx index f01e7e31c1431..00bf0e083bc1d 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx @@ -20,6 +20,8 @@ import { i18n } from '@kbn/i18n'; import { ApiKeyFlyoutWrapper } from './api_key_flyout_wrapper'; import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; +const hiddenKeyPreview = '•'.repeat(30); + export const ApiKeyForm = () => { const { euiTheme } = useEuiTheme(); const [showFlyout, setShowFlyout] = useState(false); @@ -34,7 +36,7 @@ export const ApiKeyForm = () => {
- +
@@ -42,7 +44,7 @@ export const ApiKeyForm = () => { <> - {status === Status.showHiddenKey ? '•'.repeat(30) : apiKey} + {status === Status.showHiddenKey ? hiddenKeyPreview : apiKey} {status === Status.showPreviewKey && ( @@ -51,7 +53,7 @@ export const ApiKeyForm = () => { iconType="copy" color="success" onClick={handleAddToClipboard} - aria-label={i18n.translate('xpack.searchIndices.apiKeyForm.copyButton', { + aria-label={i18n.translate('xpack.searchApiKeys.apiKeyForm.copyButton', { defaultMessage: 'Copy button', })} /> @@ -69,7 +71,7 @@ export const ApiKeyForm = () => { onClick={() => setShowFlyout(true)} > diff --git a/x-pack/plugins/search_api_keys/server/config.ts b/x-pack/plugins/search_api_keys/server/config.ts deleted file mode 100644 index d6aaa87f69d2c..0000000000000 --- a/x-pack/plugins/search_api_keys/server/config.ts +++ /dev/null @@ -1,19 +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 { schema, TypeOf } from '@kbn/config-schema'; -// import { PluginConfigDescriptor } from '@kbn/core/server'; - -// const configSchema = schema.object({ -// enabled: schema.boolean({ defaultValue: false }), -// }); - -// export type SearchApiKeysConfig = TypeOf; - -// export const config: PluginConfigDescriptor = { -// schema: configSchema, -// }; \ No newline at end of file diff --git a/x-pack/plugins/search_api_keys/server/lib/create_key.ts b/x-pack/plugins/search_api_keys/server/lib/create_key.ts index e4d57cd3aa8f4..63386fbc283da 100644 --- a/x-pack/plugins/search_api_keys/server/lib/create_key.ts +++ b/x-pack/plugins/search_api_keys/server/lib/create_key.ts @@ -22,7 +22,7 @@ export async function createAPIKey( return apiKey; } catch (e) { - logger.error(`Error creating API Key for elasticsearch start`); + logger.error(`Search API Keys: Error during creating API Key`); logger.error(e); throw e; } diff --git a/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts b/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts index 20cd6143c9999..a19aa413aca40 100644 --- a/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts +++ b/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts @@ -21,7 +21,7 @@ export async function getAPIKeyById( return apiKey.api_keys?.[0]; } catch (e) { - logger.error(`Error getting API Key for elasticsearch start`); + logger.error(`Search API Keys: Error on getting API Key`); logger.error(e); throw e; } diff --git a/x-pack/plugins/search_api_keys/server/plugin.ts b/x-pack/plugins/search_api_keys/server/plugin.ts index 0f0c12ba36d00..67550501aa8f7 100644 --- a/x-pack/plugins/search_api_keys/server/plugin.ts +++ b/x-pack/plugins/search_api_keys/server/plugin.ts @@ -27,7 +27,6 @@ export class SearchApiKeysPlugin public setup(core: CoreSetup) { this.logger.debug('searchApiKeys: Setup'); - this.logger.info('searchApiKeys test'); const router = core.http.createRouter(); // Register server side APIs diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts index df8dee8099d27..9eb24427bdc48 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -32,7 +32,6 @@ export function registerRoutes(router: IRouter, logger: Logger) { const core = await context.core; const client = core.elasticsearch.client.asCurrentUser; const apiKey = await getAPIKeyById(request.body.id, client, logger); - logger.info('API KEY' + JSON.stringify(apiKey)); if (!apiKey) { return response.customError({ diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc index be7a4ce4ca1af..6ac2b429959de 100644 --- a/x-pack/plugins/search_indices/kibana.jsonc +++ b/x-pack/plugins/search_indices/kibana.jsonc @@ -12,12 +12,12 @@ ], "requiredPlugins": [ "share", - "searchApiKeys", ], "optionalPlugins": [ "cloud", "console", "usageCollection", + "searchApiKeys" ], "requiredBundles": [ "kibanaReact", diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index 2c5dd0b1b771d..a326956635d80 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -32,11 +32,10 @@ "searchHomepage", "searchIndices", "searchInferenceEndpoints", - "usageCollection", - "searchApiKeys" + "usageCollection" ], "requiredBundles": [ "kibanaReact" ] } -} \ No newline at end of file +} From fedef8b09d2bc9f3fc245914ea0f10c02ba62edf Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:24:09 +0000 Subject: [PATCH 13/36] [CI] Auto-commit changed files from 'node scripts/lint_packages --fix' --- .github/CODEOWNERS | 2 +- docs/developer/plugin-list.asciidoc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 237291c1ada42..9ec4a91482787 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -749,6 +749,7 @@ src/plugins/screenshot_mode @elastic/appex-sharedux x-pack/examples/screenshotting_example @elastic/appex-sharedux x-pack/plugins/screenshotting @elastic/kibana-reporting-services packages/kbn-screenshotting-server @elastic/appex-sharedux +x-pack/plugins/search_api_keys @elastic/search-kibana packages/kbn-search-api-panels @elastic/search-kibana x-pack/plugins/search_assistant @elastic/search-kibana packages/kbn-search-connectors @elastic/search-kibana @@ -757,7 +758,6 @@ packages/kbn-search-errors @elastic/kibana-data-discovery examples/search_examples @elastic/kibana-data-discovery x-pack/plugins/search_homepage @elastic/search-kibana packages/kbn-search-index-documents @elastic/search-kibana -x-pack/plugins/search_api_keys @elastic/search-kibana x-pack/plugins/search_indices @elastic/search-kibana x-pack/plugins/search_inference_endpoints @elastic/search-kibana x-pack/plugins/search_notebooks @elastic/search-kibana diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 55a2a19040aec..ca6d508e8849b 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -803,6 +803,10 @@ Elastic. It uses Chromium and Puppeteer underneath to run the browser in headless mode. +|{kib-repo}blob/{branch}/x-pack/plugins/search_api_keys/README.md[searchApiKeys] +|The Search API Keys plugin is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. + + |{kib-repo}blob/{branch}/x-pack/plugins/search_assistant/README.md[searchAssistant] |This holds the Search AI Assistant which targets Search users and Serverless Elasticsearch. From 46d30a32866e17a1eb60262a6266ee04f9d52f54 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:25:04 +0000 Subject: [PATCH 14/36] [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' --- x-pack/plugins/search_api_keys/tsconfig.json | 25 ++------------------ x-pack/plugins/search_indices/tsconfig.json | 1 + 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/search_api_keys/tsconfig.json b/x-pack/plugins/search_api_keys/tsconfig.json index dc481d35327f2..160ebcba3463a 100644 --- a/x-pack/plugins/search_api_keys/tsconfig.json +++ b/x-pack/plugins/search_api_keys/tsconfig.json @@ -13,34 +13,13 @@ "@kbn/config-schema", "@kbn/core", "@kbn/core-elasticsearch-server", - "@kbn/core-http-browser", "@kbn/i18n", "@kbn/i18n-react", "@kbn/kibana-react-plugin", - "@kbn/security-plugin", - "@kbn/user-profile-components", - "@kbn/shared-ux-router", - "@kbn/shared-ux-page-kibana-template", "@kbn/navigation-plugin", - "@kbn/core-http-server", - "@kbn/share-plugin", - "@kbn/cloud-plugin", - "@kbn/actions-plugin", - "@kbn/shared-ux-utility", - "@kbn/core-lifecycle-browser", - "@kbn/stack-connectors-plugin", - "@kbn/cases-plugin", - "@kbn/triggers-actions-ui-plugin", - "@kbn/langchain", "@kbn/logging", - "@kbn/react-kibana-context-render", - "@kbn/doc-links", - "@kbn/core-logging-server-mocks", - "@kbn/analytics", - "@kbn/usage-collection-plugin", - "@kbn/console-plugin", - "@kbn/utility-types", - "@kbn/kibana-utils-plugin" + "@kbn/security-api-key-management", + "@kbn/core-security-common" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index 56b67256e5b47..42703e3ff19f3 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -34,6 +34,7 @@ "@kbn/cloud-plugin", "@kbn/search-index-documents", "@kbn/es-types", + "@kbn/search-api-keys", ], "exclude": [ "target/**/*", From 07661b29d8681c7dfb577d07f5e0a92d39e857cd Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 23 Sep 2024 14:48:09 +0100 Subject: [PATCH 15/36] add visibility for api key --- .../public/components/api_key_form.tsx | 14 +++++++++++++- .../public/hooks/use_search_api_key.ts | 4 ++++ x-pack/plugins/search_indices/kibana.jsonc | 7 ++++--- .../public/components/start/create_index_code.tsx | 6 ++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx index 00bf0e083bc1d..45f5a9941e605 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx @@ -25,7 +25,7 @@ const hiddenKeyPreview = '•'.repeat(30); export const ApiKeyForm = () => { const { euiTheme } = useEuiTheme(); const [showFlyout, setShowFlyout] = useState(false); - const { apiKey, status, handleSaveKey } = useSearchApiKey(); + const { apiKey, status, handleSaveKey, showAPIKey } = useSearchApiKey(); const handleAddToClipboard = useCallback( () => apiKey && navigator.clipboard.writeText(apiKey), [apiKey] @@ -59,6 +59,18 @@ export const ApiKeyForm = () => { />
)} + {status === Status.showHiddenKey && ( + + + + )} )} {status === Status.showCreateButton && ( diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts b/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts index 6fe6f91565b22..ee70b00cde7f4 100644 --- a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts +++ b/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts @@ -53,6 +53,9 @@ export const useSearchApiKey = () => { sessionStorage.setItem(API_KEY_STORAGE_KEY, JSON.stringify({ id, encoded })); dispatch({ type: 'SET_API_KEY', apiKey: encoded, status: Status.showPreviewKey }); }, []); + const handleShowKeyVisibility = useCallback(() => { + dispatch({ type: 'SET_STATUS', status: Status.showPreviewKey }); + }, []); const { mutateAsync: validateApiKey } = useMutation(async (id: string) => { try { if (!http?.post) { @@ -130,6 +133,7 @@ export const useSearchApiKey = () => { return { apiKey: state.apiKey, + showAPIKey: handleShowKeyVisibility, handleSaveKey, status: state.status, }; diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc index 5713860e66b8b..be1a9d6486b97 100644 --- a/x-pack/plugins/search_indices/kibana.jsonc +++ b/x-pack/plugins/search_indices/kibana.jsonc @@ -13,16 +13,17 @@ "requiredPlugins": [ "share", "indexManagement", + "searchApiKeys", ], "optionalPlugins": [ "cloud", "console", "usageCollection", - "searchApiKeys" ], "requiredBundles": [ "kibanaReact", - "esUiShared" + "esUiShared", + "searchApiKeys" ] } -} +} \ No newline at end of file diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx index 8c0f1973378b5..2df8e4a3734ff 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx @@ -9,6 +9,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; +import { ApiKeyForm } from '@kbn/search-api-keys/public'; import { AnalyticsEvents } from '../../analytics/constants'; import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples'; import { DenseVectorSeverlessCodeExamples } from '../../code_examples/create_index'; @@ -57,6 +58,11 @@ export const CreateIndexCodeView = ({ createIndexForm }: CreateIndexCodeViewProp return ( + + + + + Date: Tue, 24 Sep 2024 15:16:50 +0100 Subject: [PATCH 16/36] added FTRs + fixes to flows --- .../src/components/api_key_flyout.tsx | 8 ++ .../plugins/search_api_keys/common/index.ts | 2 + .../components/api_key_flyout_wrapper.tsx | 10 +- .../public/components/api_key_form.tsx | 26 ++++- .../public/hooks/use_search_api_key.ts | 9 +- .../search_api_keys/server/routes/routes.ts | 3 +- .../functional/page_objects/index.ts | 2 + .../functional/page_objects/svl_api_keys.ts | 108 ++++++++++++++++++ .../test_suites/search/elasticsearch_start.ts | 61 ++++++++++ .../test_suites/search/index.feature_flags.ts | 8 +- 10 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 x-pack/test_serverless/functional/page_objects/svl_api_keys.ts diff --git a/x-pack/packages/security/api_key_management/src/components/api_key_flyout.tsx b/x-pack/packages/security/api_key_management/src/components/api_key_flyout.tsx index 82c37b72dd41c..4a8fa74095957 100644 --- a/x-pack/packages/security/api_key_management/src/components/api_key_flyout.tsx +++ b/x-pack/packages/security/api_key_management/src/components/api_key_flyout.tsx @@ -96,6 +96,7 @@ interface CommonApiKeyFlyoutProps { http?: CoreStart['http']; currentUser?: AuthenticatedUser; isLoadingCurrentUser?: boolean; + defaultName?: string; defaultMetadata?: string; defaultRoleDescriptors?: string; defaultExpiration?: string; @@ -172,6 +173,7 @@ export const ApiKeyFlyout: FunctionComponent = ({ defaultExpiration, defaultMetadata, defaultRoleDescriptors, + defaultName, apiKey, canManageCrossClusterApiKeys = false, readOnly = false, @@ -250,6 +252,12 @@ export const ApiKeyFlyout: FunctionComponent = ({ } }, [defaultRoleDescriptors]); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { + if (defaultName && !apiKey) { + formik.setFieldValue('name', defaultName); + } + }, [defaultName]); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { if (defaultMetadata && !apiKey) { formik.setFieldValue('metadata', defaultMetadata); diff --git a/x-pack/plugins/search_api_keys/common/index.ts b/x-pack/plugins/search_api_keys/common/index.ts index 2906b1a96846a..9af7bdc9a9a5d 100644 --- a/x-pack/plugins/search_api_keys/common/index.ts +++ b/x-pack/plugins/search_api_keys/common/index.ts @@ -8,3 +8,5 @@ export const PLUGIN_ID = 'searchApiKeys'; export const PLUGIN_NAME = 'searchApiKeys'; export const PLUGIN_PATH = '/app/api_key'; + +export const API_KEY_NAME = 'Unrestricted API Key'; diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx index 20cfe5df7b5dc..3b2faeff1cb4f 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx @@ -8,6 +8,7 @@ import { ApiKeyFlyout } from '@kbn/security-api-key-management'; import React from 'react'; import { useCurrentUser } from '../hooks/use_current_user'; +import { API_KEY_NAME } from '../../common'; interface ApiKeyFlyoutWrapperProps { onClose: () => void; @@ -17,5 +18,12 @@ interface ApiKeyFlyoutWrapperProps { export const ApiKeyFlyoutWrapper: React.FC = ({ onClose, onSuccess }) => { const user = useCurrentUser(); - return ; + return ( + + ); }; diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx index 45f5a9941e605..43be3caf7c63f 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx +++ b/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx @@ -7,6 +7,7 @@ import React, { useCallback, useState } from 'react'; import { + EuiBadge, EuiButton, EuiButtonIcon, EuiCode, @@ -20,8 +21,6 @@ import { i18n } from '@kbn/i18n'; import { ApiKeyFlyoutWrapper } from './api_key_flyout_wrapper'; import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; -const hiddenKeyPreview = '•'.repeat(30); - export const ApiKeyForm = () => { const { euiTheme } = useEuiTheme(); const [showFlyout, setShowFlyout] = useState(false); @@ -40,11 +39,25 @@ export const ApiKeyForm = () => { - {apiKey && ( + {status === Status.showUserPrivilegesError && ( + + + {i18n.translate('xpack.searchApiKeys.apiKeyForm.noUserPrivileges', { + defaultMessage: "You don't have access to manage API keys", + })} + + + )} + {status !== Status.showCreateButton && ( <> - - {status === Status.showHiddenKey ? hiddenKeyPreview : apiKey} + + {apiKey} {status === Status.showPreviewKey && ( @@ -53,6 +66,7 @@ export const ApiKeyForm = () => { iconType="copy" color="success" onClick={handleAddToClipboard} + data-test-subj="apiKeyFormAPIKeyCopyButton" aria-label={i18n.translate('xpack.searchApiKeys.apiKeyForm.copyButton', { defaultMessage: 'Copy button', })} @@ -65,6 +79,7 @@ export const ApiKeyForm = () => { iconType="eye" color="success" onClick={showAPIKey} + data-test-subj="showAPIKeyButton" aria-label={i18n.translate('xpack.searchApiKeys.apiKeyForm.showApiKey', { defaultMessage: 'Show API Key', })} @@ -81,6 +96,7 @@ export const ApiKeyForm = () => { iconSide="left" iconType="key" onClick={() => setShowFlyout(true)} + data-test-subj="createAPIKeyButton" > { const [state, dispatch] = useReducer(reducer, initialState); const handleSaveKey = useCallback(({ id, encoded }: { id: string; encoded: string }) => { sessionStorage.setItem(API_KEY_STORAGE_KEY, JSON.stringify({ id, encoded })); - dispatch({ type: 'SET_API_KEY', apiKey: encoded, status: Status.showPreviewKey }); + dispatch({ type: 'SET_API_KEY', apiKey: encoded, status: Status.showHiddenKey }); }, []); const handleShowKeyVisibility = useCallback(() => { dispatch({ type: 'SET_STATUS', status: Status.showPreviewKey }); @@ -82,6 +84,8 @@ export const useSearchApiKey = () => { } catch (err) { if (err.response?.status === 400) { dispatch({ type: 'SET_STATUS', status: Status.showCreateButton }); + } else if (err.response?.status === 403) { + dispatch({ type: 'SET_STATUS', status: Status.showUserPrivilegesError }); } else { throw err; } @@ -121,6 +125,7 @@ export const useSearchApiKey = () => { dispatch({ type: 'CLEAR_API_KEY', }); + await createApiKey(); } } else { await createApiKey(); @@ -132,7 +137,7 @@ export const useSearchApiKey = () => { }, [validateApiKey, createApiKey]); return { - apiKey: state.apiKey, + apiKey: state.status === Status.showHiddenKey ? API_KEY_MASK : state.apiKey, showAPIKey: handleShowKeyVisibility, handleSaveKey, status: state.status, diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/x-pack/plugins/search_api_keys/server/routes/routes.ts index 9eb24427bdc48..33e29435651f9 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/x-pack/plugins/search_api_keys/server/routes/routes.ts @@ -13,6 +13,7 @@ import { APIRoutes } from '../../common/types'; import { getAPIKeyById } from '../lib/get_key_by_id'; import { createAPIKey } from '../lib/create_key'; import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; +import { API_KEY_NAME } from '../../common'; export function registerRoutes(router: IRouter, logger: Logger) { router.post( @@ -85,7 +86,7 @@ export function registerRoutes(router: IRouter, logger: Logger) { }); } - const apiKey = await createAPIKey('Onboarding API Key', client, logger); + const apiKey = await createAPIKey(API_KEY_NAME, client, logger); return response.ok({ body: apiKey, diff --git a/x-pack/test_serverless/functional/page_objects/index.ts b/x-pack/test_serverless/functional/page_objects/index.ts index 6874f1e7aa621..0c6b776433b0c 100644 --- a/x-pack/test_serverless/functional/page_objects/index.ts +++ b/x-pack/test_serverless/functional/page_objects/index.ts @@ -23,6 +23,7 @@ import { SvlIngestPipelines } from './svl_ingest_pipelines'; import { SvlSearchHomePageProvider } from './svl_search_homepage'; import { SvlSearchIndexDetailPageProvider } from './svl_search_index_detail_page'; import { SvlSearchElasticsearchStartPageProvider } from './svl_search_elasticsearch_start_page'; +import { SvlApiKeysProvider } from './svl_api_keys'; export const pageObjects = { ...xpackFunctionalPageObjects, @@ -43,4 +44,5 @@ export const pageObjects = { svlSearchHomePage: SvlSearchHomePageProvider, svlSearchIndexDetailPage: SvlSearchIndexDetailPageProvider, svlSearchElasticsearchStartPage: SvlSearchElasticsearchStartPageProvider, + svlApiKeys: SvlApiKeysProvider, }; diff --git a/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts b/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts new file mode 100644 index 0000000000000..2dc65cc97cd3e --- /dev/null +++ b/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts @@ -0,0 +1,108 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +const APIKEY_MASK = '•'.repeat(60); + +export function SvlApiKeysProvider({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const pageObjects = getPageObjects(['common', 'apiKeys']); + const retry = getService('retry'); + const es = getService('es'); + + const getAPIKeyFromSessionStorage = async () => { + const sessionStorageKey = await browser.getSessionStorageItem('searchApiKey'); + return sessionStorageKey && JSON.parse(sessionStorageKey); + }; + + return { + async clearAPIKeySessionStorage() { + await browser.clearSessionStorage(); + }, + + async expectAPIKeyAvailable() { + await testSubjects.existOrFail('apiKeyFormAPIKey'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('apiKeyFormAPIKey')).to.be(APIKEY_MASK); + }); + await testSubjects.click('showAPIKeyButton'); + let apiKey; + await retry.try(async () => { + apiKey = await testSubjects.getVisibleText('apiKeyFormAPIKey'); + expect(apiKey).to.be.a('string'); + expect(apiKey.length).to.be(60); + expect(apiKey).to.not.be(APIKEY_MASK); + }); + const sessionStorageKey = await getAPIKeyFromSessionStorage(); + expect(sessionStorageKey.encoded).to.eql(apiKey); + }, + + async getAPIKeyFromSessionStorage() { + return getAPIKeyFromSessionStorage(); + }, + + async getAPIKeyFromUI() { + let apiKey = ''; + await retry.try(async () => { + apiKey = await testSubjects.getVisibleText('apiKeyFormAPIKey'); + expect(apiKey).to.not.be(APIKEY_MASK); + }); + expect(apiKey).to.be.a('string'); + return apiKey; + }, + + async invalidateAPIKey(apiKeyId: string) { + await es.security.invalidateApiKey({ ids: [apiKeyId] }); + }, + + async createAPIKey() { + await es.security.createApiKey({ + name: 'test-api-key', + role_descriptors: {}, + }); + }, + + async expectAPIKeyCreate() { + await testSubjects.existOrFail('apiKeyFormAPIKey'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('apiKeyFormAPIKey')).to.be(APIKEY_MASK); + }); + await testSubjects.click('showAPIKeyButton'); + await retry.try(async () => { + const apiKey = await testSubjects.getVisibleText('apiKeyFormAPIKey'); + expect(apiKey).to.be.a('string'); + expect(apiKey.length).to.be(60); + expect(apiKey).to.not.be(APIKEY_MASK); + }); + }, + + async deleteAPIKeys() { + const { api_keys: apiKeys } = await es.security.getApiKey(); + await es.security.invalidateApiKey({ ids: apiKeys.map((key) => key.id) }); + }, + + async expectCreateApiKeyAction() { + await testSubjects.existOrFail('createAPIKeyButton'); + }, + + async createApiKeyFromFlyout() { + const apiKeyName = 'Happy API Key'; + await testSubjects.click('createAPIKeyButton'); + expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('Create API key'); + + await pageObjects.apiKeys.setApiKeyName(apiKeyName); + await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); + }, + + async expectNoPermissionsMessage() { + await testSubjects.existOrFail('apiKeyFormNoUserPrivileges'); + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts index 55f1551141e47..004ae75b7cda5 100644 --- a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts +++ b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts @@ -5,6 +5,7 @@ * 2.0. */ +import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; import { testHasEmbeddedConsole } from './embedded_console'; @@ -14,10 +15,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'svlCommonPage', 'embeddedConsole', 'svlSearchElasticsearchStartPage', + 'svlApiKeys', ]); const svlSearchNavigation = getService('svlSearchNavigation'); const esDeleteAllIndices = getService('esDeleteAllIndices'); const es = getService('es'); + const browser = getService('browser'); const deleteAllTestIndices = async () => { await esDeleteAllIndices(['search-*', 'test-*']); @@ -27,6 +30,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('developer', function () { before(async () => { await pageObjects.svlCommonPage.loginWithRole('developer'); + await pageObjects.svlApiKeys.deleteAPIKeys(); }); after(async () => { await deleteAllTestIndices(); @@ -81,6 +85,55 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchElasticsearchStartPage.clickUIViewButton(); await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexUIView(); }); + + it('should show the api key in code view', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const apiKeyUI = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + const apiKeySession = await pageObjects.svlApiKeys.getAPIKeyFromSessionStorage(); + + expect(apiKeyUI).to.eql(apiKeySession.encoded); + + // check that when browser is refreshed, the api key is still available + await browser.refresh(); + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const refreshBrowserApiKeyUI = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + expect(refreshBrowserApiKeyUI).to.eql(apiKeyUI); + + // check that when api key is invalidated, a new one is generated + await pageObjects.svlApiKeys.invalidateAPIKey(apiKeySession.id); + await browser.refresh(); + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const newApiKeyUI = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + expect(newApiKeyUI).to.not.eql(apiKeyUI); + }); + + it('should explicitly ask to create api key when project already has an apikey', async () => { + await pageObjects.svlApiKeys.clearAPIKeySessionStorage(); + await pageObjects.svlApiKeys.createAPIKey(); + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.createApiKeyFromFlyout(); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + }); + + it('Same API Key should be present on start page and index detail view', async () => { + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const apiKeyUI = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + + await pageObjects.svlSearchElasticsearchStartPage.clickUIViewButton(); + await pageObjects.svlSearchElasticsearchStartPage.clickCreateIndexButton(); + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnIndexDetailsPage(); + + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const indexDetailsApiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + + expect(apiKeyUI).to.eql(indexDetailsApiKey); + }); }); describe('viewer', function () { before(async () => { @@ -102,6 +155,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexButtonToBeDisabled(); }); + it('should not create an API key if the user only has viewer permissions', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.expectNoPermissionsMessage(); + const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromSessionStorage(); + expect(apiKey).to.be(null); + }); + it('should redirect to index details when index is created via API', async () => { await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexCodeView(); diff --git a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts index c5c9b82dd21cd..4dc1fc0d02c71 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts @@ -11,9 +11,9 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search UI - feature flags', function () { // add tests that require feature flags, defined in config.feature_flags.ts loadTestFile(require.resolve('./elasticsearch_start.ts')); - loadTestFile(require.resolve('./search_index_detail.ts')); - loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); - loadTestFile(require.resolve('../common/platform_security/roles.ts')); - loadTestFile(require.resolve('../common/spaces/multiple_spaces_enabled.ts')); + // loadTestFile(require.resolve('./search_index_detail.ts')); + // loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); + // loadTestFile(require.resolve('../common/platform_security/roles.ts')); + // loadTestFile(require.resolve('../common/spaces/multiple_spaces_enabled.ts')); }); } From e942537b8eea388d28da2988518a8a0b084a9eba Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Thu, 26 Sep 2024 21:57:49 +0100 Subject: [PATCH 17/36] update to package --- docs/developer/plugin-list.asciidoc | 4 -- package.json | 2 +- packages/kbn-search-api-keys/README.md | 3 + packages/kbn-search-api-keys/common/index.ts | 10 ++++ .../kbn-search-api-keys}/common/types.ts | 8 ++- .../components/api_key_flyout_wrapper.tsx | 10 ++-- .../components/api_key_form.tsx | 60 +++++++++---------- .../hooks/use_current_user.ts | 10 ++-- .../hooks/use_search_api_key.ts | 15 +++-- packages/kbn-search-api-keys/jest.config.js | 19 ++++++ packages/kbn-search-api-keys/kibana.jsonc | 5 ++ packages/kbn-search-api-keys/package.json | 6 ++ .../server/lib/create_key.ts | 31 ++++++++++ .../server/lib/get_key_by_id.ts | 30 ++++++++++ .../server/lib/privileges.ts | 12 ++-- .../server/routes/routes.ts | 10 ++-- .../kbn-search-api-keys}/tsconfig.json | 5 +- tsconfig.base.json | 4 +- x-pack/.i18nrc.json | 2 +- x-pack/plugins/search_api_keys/README.md | 3 - .../plugins/search_api_keys/common/index.ts | 12 ---- x-pack/plugins/search_api_keys/jest.config.js | 15 ----- x-pack/plugins/search_api_keys/kibana.jsonc | 23 ------- .../plugins/search_api_keys/public/index.ts | 13 ---- .../plugins/search_api_keys/public/plugin.ts | 20 ------- .../plugins/search_api_keys/server/index.ts | 15 ----- .../search_api_keys/server/lib/create_key.ts | 29 --------- .../server/lib/get_key_by_id.ts | 28 --------- .../plugins/search_api_keys/server/plugin.ts | 44 -------------- .../plugins/search_api_keys/server/types.ts | 17 ------ x-pack/plugins/search_indices/kibana.jsonc | 4 +- .../components/indices/details_page.tsx | 2 +- .../components/start/create_index_code.tsx | 2 +- .../search_indices/server/routes/index.ts | 2 + yarn.lock | 2 +- 35 files changed, 185 insertions(+), 292 deletions(-) create mode 100644 packages/kbn-search-api-keys/README.md create mode 100644 packages/kbn-search-api-keys/common/index.ts rename {x-pack/plugins/search_api_keys => packages/kbn-search-api-keys}/common/types.ts (56%) rename {x-pack/plugins/search_api_keys/public => packages/kbn-search-api-keys}/components/api_key_flyout_wrapper.tsx (60%) rename {x-pack/plugins/search_api_keys/public => packages/kbn-search-api-keys}/components/api_key_form.tsx (66%) rename {x-pack/plugins/search_api_keys/public => packages/kbn-search-api-keys}/hooks/use_current_user.ts (59%) rename {x-pack/plugins/search_api_keys/public => packages/kbn-search-api-keys}/hooks/use_search_api_key.ts (87%) create mode 100644 packages/kbn-search-api-keys/jest.config.js create mode 100644 packages/kbn-search-api-keys/kibana.jsonc create mode 100644 packages/kbn-search-api-keys/package.json create mode 100644 packages/kbn-search-api-keys/server/lib/create_key.ts create mode 100644 packages/kbn-search-api-keys/server/lib/get_key_by_id.ts rename {x-pack/plugins/search_api_keys => packages/kbn-search-api-keys}/server/lib/privileges.ts (68%) rename {x-pack/plugins/search_api_keys => packages/kbn-search-api-keys}/server/routes/routes.ts (85%) rename {x-pack/plugins/search_api_keys => packages/kbn-search-api-keys}/tsconfig.json (87%) delete mode 100644 x-pack/plugins/search_api_keys/README.md delete mode 100644 x-pack/plugins/search_api_keys/common/index.ts delete mode 100644 x-pack/plugins/search_api_keys/jest.config.js delete mode 100644 x-pack/plugins/search_api_keys/kibana.jsonc delete mode 100644 x-pack/plugins/search_api_keys/public/index.ts delete mode 100644 x-pack/plugins/search_api_keys/public/plugin.ts delete mode 100644 x-pack/plugins/search_api_keys/server/index.ts delete mode 100644 x-pack/plugins/search_api_keys/server/lib/create_key.ts delete mode 100644 x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts delete mode 100644 x-pack/plugins/search_api_keys/server/plugin.ts delete mode 100644 x-pack/plugins/search_api_keys/server/types.ts diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index ca6d508e8849b..55a2a19040aec 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -803,10 +803,6 @@ Elastic. It uses Chromium and Puppeteer underneath to run the browser in headless mode. -|{kib-repo}blob/{branch}/x-pack/plugins/search_api_keys/README.md[searchApiKeys] -|The Search API Keys plugin is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. - - |{kib-repo}blob/{branch}/x-pack/plugins/search_assistant/README.md[searchAssistant] |This holds the Search AI Assistant which targets Search users and Serverless Elasticsearch. diff --git a/package.json b/package.json index e0af889021c2c..25d8704fa0bac 100644 --- a/package.json +++ b/package.json @@ -769,7 +769,7 @@ "@kbn/screenshotting-example-plugin": "link:x-pack/examples/screenshotting_example", "@kbn/screenshotting-plugin": "link:x-pack/plugins/screenshotting", "@kbn/screenshotting-server": "link:packages/kbn-screenshotting-server", - "@kbn/search-api-keys": "link:x-pack/plugins/search_api_keys", + "@kbn/search-api-keys": "link:packages/kbn-search-api-keys", "@kbn/search-api-panels": "link:packages/kbn-search-api-panels", "@kbn/search-assistant": "link:x-pack/plugins/search_assistant", "@kbn/search-connectors": "link:packages/kbn-search-connectors", diff --git a/packages/kbn-search-api-keys/README.md b/packages/kbn-search-api-keys/README.md new file mode 100644 index 0000000000000..82a42ad81b5b6 --- /dev/null +++ b/packages/kbn-search-api-keys/README.md @@ -0,0 +1,3 @@ +# Search API Keys + +The Search API Keys package is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. \ No newline at end of file diff --git a/packages/kbn-search-api-keys/common/index.ts b/packages/kbn-search-api-keys/common/index.ts new file mode 100644 index 0000000000000..be967ed8eb4eb --- /dev/null +++ b/packages/kbn-search-api-keys/common/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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export const API_KEY_NAME = 'Unrestricted API Key'; diff --git a/x-pack/plugins/search_api_keys/common/types.ts b/packages/kbn-search-api-keys/common/types.ts similarity index 56% rename from x-pack/plugins/search_api_keys/common/types.ts rename to packages/kbn-search-api-keys/common/types.ts index b0efe74bbc0e7..6f7ff29493ffd 100644 --- a/x-pack/plugins/search_api_keys/common/types.ts +++ b/packages/kbn-search-api-keys/common/types.ts @@ -1,8 +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; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ export enum APIRoutes { diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx b/packages/kbn-search-api-keys/components/api_key_flyout_wrapper.tsx similarity index 60% rename from x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx rename to packages/kbn-search-api-keys/components/api_key_flyout_wrapper.tsx index 3b2faeff1cb4f..fbdd137077e66 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_flyout_wrapper.tsx +++ b/packages/kbn-search-api-keys/components/api_key_flyout_wrapper.tsx @@ -1,14 +1,16 @@ /* * 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. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { ApiKeyFlyout } from '@kbn/security-api-key-management'; import React from 'react'; import { useCurrentUser } from '../hooks/use_current_user'; -import { API_KEY_NAME } from '../../common'; +import { API_KEY_NAME } from '../common'; interface ApiKeyFlyoutWrapperProps { onClose: () => void; diff --git a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx b/packages/kbn-search-api-keys/components/api_key_form.tsx similarity index 66% rename from x-pack/plugins/search_api_keys/public/components/api_key_form.tsx rename to packages/kbn-search-api-keys/components/api_key_form.tsx index 43be3caf7c63f..488cd7b51632d 100644 --- a/x-pack/plugins/search_api_keys/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys/components/api_key_form.tsx @@ -1,8 +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; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import React, { useCallback, useState } from 'react'; @@ -24,7 +26,7 @@ import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; export const ApiKeyForm = () => { const { euiTheme } = useEuiTheme(); const [showFlyout, setShowFlyout] = useState(false); - const { apiKey, status, handleSaveKey, showAPIKey } = useSearchApiKey(); + const { apiKey, status, handleSaveKey, showAPIKey, displayedApiKey } = useSearchApiKey(); const handleAddToClipboard = useCallback( () => apiKey && navigator.clipboard.writeText(apiKey), [apiKey] @@ -57,35 +59,31 @@ export const ApiKeyForm = () => { css={{ color: euiTheme.colors.successText }} data-test-subj="apiKeyFormAPIKey" > - {apiKey} + {displayedApiKey} - {status === Status.showPreviewKey && ( - - - - )} - {status === Status.showHiddenKey && ( - - - - )} + + + + + + )} {status === Status.showCreateButton && ( diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts b/packages/kbn-search-api-keys/hooks/use_current_user.ts similarity index 59% rename from x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts rename to packages/kbn-search-api-keys/hooks/use_current_user.ts index 377d32ccc24b5..06b719adea806 100644 --- a/x-pack/plugins/search_api_keys/public/hooks/use_current_user.ts +++ b/packages/kbn-search-api-keys/hooks/use_current_user.ts @@ -1,13 +1,15 @@ /* * 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. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { useState, useEffect } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { AuthenticatedUser } from '@kbn/core-security-common'; +import type { AuthenticatedUser } from '@kbn/core-security-common'; export const useCurrentUser = () => { const { security } = useKibana().services; diff --git a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts b/packages/kbn-search-api-keys/hooks/use_search_api_key.ts similarity index 87% rename from x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts rename to packages/kbn-search-api-keys/hooks/use_search_api_key.ts index 242d570eb2035..49b99562ed7f8 100644 --- a/x-pack/plugins/search_api_keys/public/hooks/use_search_api_key.ts +++ b/packages/kbn-search-api-keys/hooks/use_search_api_key.ts @@ -1,13 +1,17 @@ /* * 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. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ + import { useEffect, useCallback, useReducer } from 'react'; import { useMutation } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { APIKeyCreationResponse, APIRoutes } from '../../common/types'; +import type { APIKeyCreationResponse } from '../common/types'; +import { APIRoutes } from '../common/types'; const API_KEY_STORAGE_KEY = 'searchApiKey'; const API_KEY_MASK = '•'.repeat(60); @@ -137,7 +141,8 @@ export const useSearchApiKey = () => { }, [validateApiKey, createApiKey]); return { - apiKey: state.status === Status.showHiddenKey ? API_KEY_MASK : state.apiKey, + displayedApiKey: state.status === Status.showHiddenKey ? API_KEY_MASK : state.apiKey, + apiKey: state.apiKey, showAPIKey: handleShowKeyVisibility, handleSaveKey, status: state.status, diff --git a/packages/kbn-search-api-keys/jest.config.js b/packages/kbn-search-api-keys/jest.config.js new file mode 100644 index 0000000000000..da7a1c6061491 --- /dev/null +++ b/packages/kbn-search-api-keys/jest.config.js @@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/plugins/search_api_keys'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_api_keys', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/search_api_keys/{common,components,hooks,server}/**/*.{ts,tsx}', + ], +}; diff --git a/packages/kbn-search-api-keys/kibana.jsonc b/packages/kbn-search-api-keys/kibana.jsonc new file mode 100644 index 0000000000000..ad8fd270238ae --- /dev/null +++ b/packages/kbn-search-api-keys/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/search-api-keys", + "owner": "@elastic/search-kibana" +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys/package.json b/packages/kbn-search-api-keys/package.json new file mode 100644 index 0000000000000..aaddf66dad759 --- /dev/null +++ b/packages/kbn-search-api-keys/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/search-api-keys", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys/server/lib/create_key.ts b/packages/kbn-search-api-keys/server/lib/create_key.ts new file mode 100644 index 0000000000000..982fdb24ae32c --- /dev/null +++ b/packages/kbn-search-api-keys/server/lib/create_key.ts @@ -0,0 +1,31 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { Logger } from '@kbn/logging'; +import type { APIKeyCreationResponse } from '../../common/types'; + +export async function createAPIKey( + name: string, + client: ElasticsearchClient, + logger: Logger +): Promise { + try { + const apiKey = await client.security.createApiKey({ + name, + role_descriptors: {}, + }); + + return apiKey; + } catch (e) { + logger.error(`Search API Keys: Error during creating API Key`); + logger.error(e); + throw e; + } +} diff --git a/packages/kbn-search-api-keys/server/lib/get_key_by_id.ts b/packages/kbn-search-api-keys/server/lib/get_key_by_id.ts new file mode 100644 index 0000000000000..57c7d3e6253b8 --- /dev/null +++ b/packages/kbn-search-api-keys/server/lib/get_key_by_id.ts @@ -0,0 +1,30 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { Logger } from '@kbn/logging'; +import type { GetApiKeyResponse } from '../../common/types'; + +export async function getAPIKeyById( + id: string, + client: ElasticsearchClient, + logger: Logger +): Promise { + try { + const apiKey = await client.security.getApiKey({ + id, + }); + + return apiKey.api_keys?.[0]; + } catch (e) { + logger.error(`Search API Keys: Error on getting API Key`); + logger.error(e); + throw e; + } +} diff --git a/x-pack/plugins/search_api_keys/server/lib/privileges.ts b/packages/kbn-search-api-keys/server/lib/privileges.ts similarity index 68% rename from x-pack/plugins/search_api_keys/server/lib/privileges.ts rename to packages/kbn-search-api-keys/server/lib/privileges.ts index d956e1d74e873..fc5ad1f896746 100644 --- a/x-pack/plugins/search_api_keys/server/lib/privileges.ts +++ b/packages/kbn-search-api-keys/server/lib/privileges.ts @@ -1,12 +1,14 @@ /* * 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. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { Logger } from '@kbn/logging'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { Logger } from '@kbn/logging'; export async function fetchUserStartPrivileges( client: ElasticsearchClient, diff --git a/x-pack/plugins/search_api_keys/server/routes/routes.ts b/packages/kbn-search-api-keys/server/routes/routes.ts similarity index 85% rename from x-pack/plugins/search_api_keys/server/routes/routes.ts rename to packages/kbn-search-api-keys/server/routes/routes.ts index 33e29435651f9..a3d412a4609ab 100644 --- a/x-pack/plugins/search_api_keys/server/routes/routes.ts +++ b/packages/kbn-search-api-keys/server/routes/routes.ts @@ -1,8 +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; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import type { IRouter } from '@kbn/core/server'; @@ -15,7 +17,7 @@ import { createAPIKey } from '../lib/create_key'; import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; import { API_KEY_NAME } from '../../common'; -export function registerRoutes(router: IRouter, logger: Logger) { +export function registerSearchApiKeysRoutes(router: IRouter, logger: Logger) { router.post( { path: APIRoutes.API_KEY_VALIDITY, diff --git a/x-pack/plugins/search_api_keys/tsconfig.json b/packages/kbn-search-api-keys/tsconfig.json similarity index 87% rename from x-pack/plugins/search_api_keys/tsconfig.json rename to packages/kbn-search-api-keys/tsconfig.json index 160ebcba3463a..11e85314f249c 100644 --- a/x-pack/plugins/search_api_keys/tsconfig.json +++ b/packages/kbn-search-api-keys/tsconfig.json @@ -1,10 +1,9 @@ { - "extends": "../../../tsconfig.base.json", + "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "target/types", }, "include": [ - "__mocks__/**/*", "common/**/*", "public/**/*", "server/**/*", @@ -24,4 +23,4 @@ "exclude": [ "target/**/*", ] -} +} \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index df68b0924669c..b9526fbc04a0c 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1498,8 +1498,8 @@ "@kbn/screenshotting-plugin/*": ["x-pack/plugins/screenshotting/*"], "@kbn/screenshotting-server": ["packages/kbn-screenshotting-server"], "@kbn/screenshotting-server/*": ["packages/kbn-screenshotting-server/*"], - "@kbn/search-api-keys": ["x-pack/plugins/search_api_keys"], - "@kbn/search-api-keys/*": ["x-pack/plugins/search_api_keys/*"], + "@kbn/search-api-keys": ["packages/kbn-search-api-keys"], + "@kbn/search-api-keys/*": ["packages/kbn-search-api-keys/*"], "@kbn/search-api-panels": ["packages/kbn-search-api-panels"], "@kbn/search-api-panels/*": ["packages/kbn-search-api-panels/*"], "@kbn/search-assistant": ["x-pack/plugins/search_assistant"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 7da1085e78e80..d4b63420d6870 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -106,7 +106,7 @@ "xpack.screenshotting": "plugins/screenshotting", "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchIndices": "plugins/search_indices", - "xpack.searchApiKeys": "plugins/search_api_keys", + "xpack.searchApiKeys": "packages/search-api-keys", "xpack.searchNotebooks": "plugins/search_notebooks", "xpack.searchPlayground": "plugins/search_playground", "xpack.searchInferenceEndpoints": "plugins/search_inference_endpoints", diff --git a/x-pack/plugins/search_api_keys/README.md b/x-pack/plugins/search_api_keys/README.md deleted file mode 100644 index 0b90c191667cc..0000000000000 --- a/x-pack/plugins/search_api_keys/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Search API Keys - -The Search API Keys plugin is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. \ No newline at end of file diff --git a/x-pack/plugins/search_api_keys/common/index.ts b/x-pack/plugins/search_api_keys/common/index.ts deleted file mode 100644 index 9af7bdc9a9a5d..0000000000000 --- a/x-pack/plugins/search_api_keys/common/index.ts +++ /dev/null @@ -1,12 +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. - */ - -export const PLUGIN_ID = 'searchApiKeys'; -export const PLUGIN_NAME = 'searchApiKeys'; -export const PLUGIN_PATH = '/app/api_key'; - -export const API_KEY_NAME = 'Unrestricted API Key'; diff --git a/x-pack/plugins/search_api_keys/jest.config.js b/x-pack/plugins/search_api_keys/jest.config.js deleted file mode 100644 index 288bf405db513..0000000000000 --- a/x-pack/plugins/search_api_keys/jest.config.js +++ /dev/null @@ -1,15 +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. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../../..', - roots: ['/x-pack/plugins/search_api_keys'], - coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_api_keys', - coverageReporters: ['text', 'html'], - collectCoverageFrom: ['/x-pack/plugins/search_api_keys/{public,server}/**/*.{ts,tsx}'], -}; diff --git a/x-pack/plugins/search_api_keys/kibana.jsonc b/x-pack/plugins/search_api_keys/kibana.jsonc deleted file mode 100644 index 2d95bcbe778ec..0000000000000 --- a/x-pack/plugins/search_api_keys/kibana.jsonc +++ /dev/null @@ -1,23 +0,0 @@ -{ - "type": "plugin", - "id": "@kbn/search-api-keys", - "owner": "@elastic/search-kibana", - "plugin": { - "id": "searchApiKeys", - "server": true, - "browser": true, - "configPath": [ - "xpack", - "searchApiKeys" - ], - "requiredPlugins": [ - "kibanaReact", - ], - "optionalPlugins": [ - "cloud", - "console", - "usageCollection", - ], - "requiredBundles": [] - } -} diff --git a/x-pack/plugins/search_api_keys/public/index.ts b/x-pack/plugins/search_api_keys/public/index.ts deleted file mode 100644 index 5c4f6e5773e40..0000000000000 --- a/x-pack/plugins/search_api_keys/public/index.ts +++ /dev/null @@ -1,13 +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 { SearchApiKeysPlugin } from './plugin'; - -export { ApiKeyForm } from './components/api_key_form'; - -export function plugin() { - return new SearchApiKeysPlugin(); -} diff --git a/x-pack/plugins/search_api_keys/public/plugin.ts b/x-pack/plugins/search_api_keys/public/plugin.ts deleted file mode 100644 index 458b8b42c05d3..0000000000000 --- a/x-pack/plugins/search_api_keys/public/plugin.ts +++ /dev/null @@ -1,20 +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 type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; - -export class SearchApiKeysPlugin implements Plugin<{}, {}> { - public setup(core: CoreSetup): {} { - return {}; - } - - public start(core: CoreStart): {} { - return {}; - } - - public stop() {} -} diff --git a/x-pack/plugins/search_api_keys/server/index.ts b/x-pack/plugins/search_api_keys/server/index.ts deleted file mode 100644 index d2d6cc83ba9d9..0000000000000 --- a/x-pack/plugins/search_api_keys/server/index.ts +++ /dev/null @@ -1,15 +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 { PluginInitializerContext } from '@kbn/core/server'; - -// export { config } from './config'; - -export async function plugin(initializerContext: PluginInitializerContext) { - const { SearchApiKeysPlugin } = await import('./plugin'); - return new SearchApiKeysPlugin(initializerContext); -} diff --git a/x-pack/plugins/search_api_keys/server/lib/create_key.ts b/x-pack/plugins/search_api_keys/server/lib/create_key.ts deleted file mode 100644 index 63386fbc283da..0000000000000 --- a/x-pack/plugins/search_api_keys/server/lib/create_key.ts +++ /dev/null @@ -1,29 +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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { Logger } from '@kbn/logging'; -import { APIKeyCreationResponse } from '../../common/types'; - -export async function createAPIKey( - name: string, - client: ElasticsearchClient, - logger: Logger -): Promise { - try { - const apiKey = await client.security.createApiKey({ - name, - role_descriptors: {}, - }); - - return apiKey; - } catch (e) { - logger.error(`Search API Keys: Error during creating API Key`); - logger.error(e); - throw e; - } -} diff --git a/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts b/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts deleted file mode 100644 index a19aa413aca40..0000000000000 --- a/x-pack/plugins/search_api_keys/server/lib/get_key_by_id.ts +++ /dev/null @@ -1,28 +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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { Logger } from '@kbn/logging'; -import { GetApiKeyResponse } from '../../common/types'; - -export async function getAPIKeyById( - id: string, - client: ElasticsearchClient, - logger: Logger -): Promise { - try { - const apiKey = await client.security.getApiKey({ - id, - }); - - return apiKey.api_keys?.[0]; - } catch (e) { - logger.error(`Search API Keys: Error on getting API Key`); - logger.error(e); - throw e; - } -} diff --git a/x-pack/plugins/search_api_keys/server/plugin.ts b/x-pack/plugins/search_api_keys/server/plugin.ts deleted file mode 100644 index 67550501aa8f7..0000000000000 --- a/x-pack/plugins/search_api_keys/server/plugin.ts +++ /dev/null @@ -1,44 +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 type { - PluginInitializerContext, - CoreSetup, - CoreStart, - Plugin, - Logger, -} from '@kbn/core/server'; - -import type { SearchApiKeysPluginSetup, SearchApiKeysPluginStart } from './types'; -import { registerRoutes } from './routes/routes'; - -export class SearchApiKeysPlugin - implements Plugin -{ - private readonly logger: Logger; - - constructor(initializerContext: PluginInitializerContext) { - this.logger = initializerContext.logger.get(); - } - - public setup(core: CoreSetup) { - this.logger.debug('searchApiKeys: Setup'); - const router = core.http.createRouter(); - - // Register server side APIs - registerRoutes(router, this.logger); - - return {}; - } - - public start(core: CoreStart) { - this.logger.debug('searchApiKeys: Started'); - return {}; - } - - public stop() {} -} diff --git a/x-pack/plugins/search_api_keys/server/types.ts b/x-pack/plugins/search_api_keys/server/types.ts deleted file mode 100644 index 31e44cd9e56ab..0000000000000 --- a/x-pack/plugins/search_api_keys/server/types.ts +++ /dev/null @@ -1,17 +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 type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SearchApiKeysPluginSetup {} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SearchApiKeysPluginStart {} - -export interface AppPluginStartDependencies { - navigation: NavigationPublicPluginStart; -} diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc index be1a9d6486b97..13abaf63cbbe3 100644 --- a/x-pack/plugins/search_indices/kibana.jsonc +++ b/x-pack/plugins/search_indices/kibana.jsonc @@ -13,7 +13,6 @@ "requiredPlugins": [ "share", "indexManagement", - "searchApiKeys", ], "optionalPlugins": [ "cloud", @@ -22,8 +21,7 @@ ], "requiredBundles": [ "kibanaReact", - "esUiShared", - "searchApiKeys" + "esUiShared" ] } } \ No newline at end of file diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx index 1b6e3e4d77471..2e79175cd076b 100644 --- a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx @@ -26,7 +26,7 @@ import { useParams } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; -import { ApiKeyForm } from '@kbn/search-api-keys/public'; +import { ApiKeyForm } from '@kbn/search-api-keys/components/api_key_form'; import { useIndex } from '../../hooks/api/use_index'; import { useKibana } from '../../hooks/use_kibana'; import { ConnectionDetails } from '../connection_details/connection_details'; diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx index d9904fe701520..8c23530a6b07e 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx @@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; -import { ApiKeyForm } from '@kbn/search-api-keys/public'; +import { ApiKeyForm } from '@kbn/search-api-keys/components/api_key_form'; import { AnalyticsEvents } from '../../analytics/constants'; import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples'; import { DenseVectorSeverlessCodeExamples } from '../../code_examples/create_index'; diff --git a/x-pack/plugins/search_indices/server/routes/index.ts b/x-pack/plugins/search_indices/server/routes/index.ts index 532ad1c3d5f3f..222c4dc4a2311 100644 --- a/x-pack/plugins/search_indices/server/routes/index.ts +++ b/x-pack/plugins/search_indices/server/routes/index.ts @@ -8,10 +8,12 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; +import { registerSearchApiKeysRoutes } from '@kbn/search-api-keys/server/routes/routes'; import { registerIndicesRoutes } from './indices'; import { registerStatusRoutes } from './status'; export function defineRoutes(router: IRouter, logger: Logger) { registerIndicesRoutes(router, logger); registerStatusRoutes(router, logger); + registerSearchApiKeysRoutes(router, logger); } diff --git a/yarn.lock b/yarn.lock index 89d52a613a0fc..5738d08f658b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6267,7 +6267,7 @@ version "0.0.0" uid "" -"@kbn/search-api-keys@link:x-pack/plugins/search_api_keys": +"@kbn/search-api-keys@link:packages/kbn-search-api-keys": version "0.0.0" uid "" From 40e9973acbc0e5fc15b5a1d24d5f93be581be956 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 27 Sep 2024 13:36:21 +0100 Subject: [PATCH 18/36] moving to a package --- package.json | 3 +- .../README.md | 0 .../kbn-search-api-keys-api/jest.config.js | 17 ++++++++ packages/kbn-search-api-keys-api/kibana.jsonc | 5 +++ .../package.json | 2 +- .../server/lib/create_key.ts | 2 +- .../server/lib/get_key_by_id.ts | 2 +- .../server/lib/privileges.ts | 0 .../server/routes/routes.ts | 5 ++- .../kbn-search-api-keys-api/tsconfig.json | 13 ++++++ .../types.ts | 0 .../kbn-search-api-keys-components/README.md | 3 ++ .../jest.config.js | 7 ++-- .../kibana.jsonc | 5 +++ .../package.json | 6 +++ .../components/api_key_flyout_wrapper.tsx | 28 +++++-------- .../public}/components/api_key_form.tsx | 41 +++++++++++-------- .../public}/hooks/use_search_api_key.ts | 4 +- .../public}/index.ts | 4 +- .../tsconfig.json | 5 +-- .../kbn-search-api-keys-components/types.ts | 13 ++++++ .../hooks/use_current_user.ts | 31 -------------- packages/kbn-search-api-keys/kibana.jsonc | 5 --- tsconfig.base.json | 6 ++- .../components/indices/details_page.tsx | 2 +- .../components/start/create_index_code.tsx | 2 +- .../search_indices/server/routes/index.ts | 2 +- yarn.lock | 6 ++- 28 files changed, 128 insertions(+), 91 deletions(-) rename packages/{kbn-search-api-keys => kbn-search-api-keys-api}/README.md (100%) create mode 100644 packages/kbn-search-api-keys-api/jest.config.js create mode 100644 packages/kbn-search-api-keys-api/kibana.jsonc rename packages/{kbn-search-api-keys => kbn-search-api-keys-api}/package.json (73%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-api}/server/lib/create_key.ts (93%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-api}/server/lib/get_key_by_id.ts (93%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-api}/server/lib/privileges.ts (100%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-api}/server/routes/routes.ts (97%) create mode 100644 packages/kbn-search-api-keys-api/tsconfig.json rename packages/{kbn-search-api-keys/common => kbn-search-api-keys-api}/types.ts (100%) create mode 100644 packages/kbn-search-api-keys-components/README.md rename packages/{kbn-search-api-keys => kbn-search-api-keys-components}/jest.config.js (69%) create mode 100644 packages/kbn-search-api-keys-components/kibana.jsonc create mode 100644 packages/kbn-search-api-keys-components/package.json rename packages/{kbn-search-api-keys => kbn-search-api-keys-components/public}/components/api_key_flyout_wrapper.tsx (52%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-components/public}/components/api_key_form.tsx (77%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-components/public}/hooks/use_search_api_key.ts (97%) rename packages/{kbn-search-api-keys/common => kbn-search-api-keys-components/public}/index.ts (77%) rename packages/{kbn-search-api-keys => kbn-search-api-keys-components}/tsconfig.json (89%) create mode 100644 packages/kbn-search-api-keys-components/types.ts delete mode 100644 packages/kbn-search-api-keys/hooks/use_current_user.ts delete mode 100644 packages/kbn-search-api-keys/kibana.jsonc diff --git a/package.json b/package.json index 25d8704fa0bac..7a7dda7edcf31 100644 --- a/package.json +++ b/package.json @@ -769,7 +769,8 @@ "@kbn/screenshotting-example-plugin": "link:x-pack/examples/screenshotting_example", "@kbn/screenshotting-plugin": "link:x-pack/plugins/screenshotting", "@kbn/screenshotting-server": "link:packages/kbn-screenshotting-server", - "@kbn/search-api-keys": "link:packages/kbn-search-api-keys", + "@kbn/search-api-keys-api": "link:packages/kbn-search-api-keys-api", + "@kbn/search-api-keys-components": "link:packages/kbn-search-api-keys-components", "@kbn/search-api-panels": "link:packages/kbn-search-api-panels", "@kbn/search-assistant": "link:x-pack/plugins/search_assistant", "@kbn/search-connectors": "link:packages/kbn-search-connectors", diff --git a/packages/kbn-search-api-keys/README.md b/packages/kbn-search-api-keys-api/README.md similarity index 100% rename from packages/kbn-search-api-keys/README.md rename to packages/kbn-search-api-keys-api/README.md diff --git a/packages/kbn-search-api-keys-api/jest.config.js b/packages/kbn-search-api-keys-api/jest.config.js new file mode 100644 index 0000000000000..695232991aaee --- /dev/null +++ b/packages/kbn-search-api-keys-api/jest.config.js @@ -0,0 +1,17 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/packages/kbn-search-api-keys-api'], + coverageDirectory: '/target/kibana-coverage/jest/packages/kbn-search-api-keys-api', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/packages/kbn-search-api-keys-api/{server}/**/*.{ts,tsx}'], +}; diff --git a/packages/kbn-search-api-keys-api/kibana.jsonc b/packages/kbn-search-api-keys-api/kibana.jsonc new file mode 100644 index 0000000000000..36501e7f34e51 --- /dev/null +++ b/packages/kbn-search-api-keys-api/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-server", + "id": "@kbn/search-api-keys-api", + "owner": "@elastic/search-kibana" +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys/package.json b/packages/kbn-search-api-keys-api/package.json similarity index 73% rename from packages/kbn-search-api-keys/package.json rename to packages/kbn-search-api-keys-api/package.json index aaddf66dad759..536a7df06d1aa 100644 --- a/packages/kbn-search-api-keys/package.json +++ b/packages/kbn-search-api-keys-api/package.json @@ -1,5 +1,5 @@ { - "name": "@kbn/search-api-keys", + "name": "@kbn/search-api-keys-api", "private": true, "version": "1.0.0", "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" diff --git a/packages/kbn-search-api-keys/server/lib/create_key.ts b/packages/kbn-search-api-keys-api/server/lib/create_key.ts similarity index 93% rename from packages/kbn-search-api-keys/server/lib/create_key.ts rename to packages/kbn-search-api-keys-api/server/lib/create_key.ts index 982fdb24ae32c..7bebe713810c8 100644 --- a/packages/kbn-search-api-keys/server/lib/create_key.ts +++ b/packages/kbn-search-api-keys-api/server/lib/create_key.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; -import type { APIKeyCreationResponse } from '../../common/types'; +import type { APIKeyCreationResponse } from '../../types'; export async function createAPIKey( name: string, diff --git a/packages/kbn-search-api-keys/server/lib/get_key_by_id.ts b/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts similarity index 93% rename from packages/kbn-search-api-keys/server/lib/get_key_by_id.ts rename to packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts index 57c7d3e6253b8..94ae64f56c0da 100644 --- a/packages/kbn-search-api-keys/server/lib/get_key_by_id.ts +++ b/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; -import type { GetApiKeyResponse } from '../../common/types'; +import type { GetApiKeyResponse } from '../../types'; export async function getAPIKeyById( id: string, diff --git a/packages/kbn-search-api-keys/server/lib/privileges.ts b/packages/kbn-search-api-keys-api/server/lib/privileges.ts similarity index 100% rename from packages/kbn-search-api-keys/server/lib/privileges.ts rename to packages/kbn-search-api-keys-api/server/lib/privileges.ts diff --git a/packages/kbn-search-api-keys/server/routes/routes.ts b/packages/kbn-search-api-keys-api/server/routes/routes.ts similarity index 97% rename from packages/kbn-search-api-keys/server/routes/routes.ts rename to packages/kbn-search-api-keys-api/server/routes/routes.ts index a3d412a4609ab..77a08644f34a5 100644 --- a/packages/kbn-search-api-keys/server/routes/routes.ts +++ b/packages/kbn-search-api-keys-api/server/routes/routes.ts @@ -11,11 +11,12 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import { schema } from '@kbn/config-schema'; -import { APIRoutes } from '../../common/types'; +import { APIRoutes } from '../../types'; import { getAPIKeyById } from '../lib/get_key_by_id'; import { createAPIKey } from '../lib/create_key'; import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; -import { API_KEY_NAME } from '../../common'; + +const API_KEY_NAME = 'Unrestricted API Key'; export function registerSearchApiKeysRoutes(router: IRouter, logger: Logger) { router.post( diff --git a/packages/kbn-search-api-keys-api/tsconfig.json b/packages/kbn-search-api-keys-api/tsconfig.json new file mode 100644 index 0000000000000..6ee9003bd7e75 --- /dev/null +++ b/packages/kbn-search-api-keys-api/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + }, + "include": [ + "server/**/*", + ], + "kbn_references": [], + "exclude": [ + "target/**/*", + ] +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys/common/types.ts b/packages/kbn-search-api-keys-api/types.ts similarity index 100% rename from packages/kbn-search-api-keys/common/types.ts rename to packages/kbn-search-api-keys-api/types.ts diff --git a/packages/kbn-search-api-keys-components/README.md b/packages/kbn-search-api-keys-components/README.md new file mode 100644 index 0000000000000..82a42ad81b5b6 --- /dev/null +++ b/packages/kbn-search-api-keys-components/README.md @@ -0,0 +1,3 @@ +# Search API Keys + +The Search API Keys package is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. \ No newline at end of file diff --git a/packages/kbn-search-api-keys/jest.config.js b/packages/kbn-search-api-keys-components/jest.config.js similarity index 69% rename from packages/kbn-search-api-keys/jest.config.js rename to packages/kbn-search-api-keys-components/jest.config.js index da7a1c6061491..f6c992d97de10 100644 --- a/packages/kbn-search-api-keys/jest.config.js +++ b/packages/kbn-search-api-keys-components/jest.config.js @@ -10,10 +10,11 @@ module.exports = { preset: '@kbn/test', rootDir: '../../..', - roots: ['/x-pack/plugins/search_api_keys'], - coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_api_keys', + roots: ['/packages/kbn-search-api-keys-components'], + coverageDirectory: + '/target/kibana-coverage/jest/packages/kbn-search-api-keys-components', coverageReporters: ['text', 'html'], collectCoverageFrom: [ - '/x-pack/plugins/search_api_keys/{common,components,hooks,server}/**/*.{ts,tsx}', + '/packages/kbn-search-api-keys-components/public/{components,hooks}/**/*.{ts,tsx}', ], }; diff --git a/packages/kbn-search-api-keys-components/kibana.jsonc b/packages/kbn-search-api-keys-components/kibana.jsonc new file mode 100644 index 0000000000000..bedd4c213760f --- /dev/null +++ b/packages/kbn-search-api-keys-components/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/search-api-keys-components", + "owner": "@elastic/search-kibana" +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys-components/package.json b/packages/kbn-search-api-keys-components/package.json new file mode 100644 index 0000000000000..1405cb6c27bed --- /dev/null +++ b/packages/kbn-search-api-keys-components/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/search-api-keys-components", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys/components/api_key_flyout_wrapper.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx similarity index 52% rename from packages/kbn-search-api-keys/components/api_key_flyout_wrapper.tsx rename to packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx index fbdd137077e66..6eaab8d0865ed 100644 --- a/packages/kbn-search-api-keys/components/api_key_flyout_wrapper.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx @@ -7,25 +7,19 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ApiKeyFlyout } from '@kbn/security-api-key-management'; +import { ApiKeyFlyout, ApiKeyFlyoutProps } from '@kbn/security-api-key-management'; import React from 'react'; -import { useCurrentUser } from '../hooks/use_current_user'; -import { API_KEY_NAME } from '../common'; +import type { SecurityCreateApiKeyResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -interface ApiKeyFlyoutWrapperProps { - onClose: () => void; - onSuccess: (apiKey: { id: string; encoded: string }) => void; -} +const API_KEY_NAME = 'Unrestricted API Key'; -export const ApiKeyFlyoutWrapper: React.FC = ({ onClose, onSuccess }) => { - const user = useCurrentUser(); +type ApiKeyFlyoutWrapperProps = Pick & { + onSuccess?: (createApiKeyResponse: SecurityCreateApiKeyResponse) => void; +}; - return ( - - ); +export const ApiKeyFlyoutWrapper: React.FC = ({ + onCancel, + onSuccess, +}) => { + return ; }; diff --git a/packages/kbn-search-api-keys/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx similarity index 77% rename from packages/kbn-search-api-keys/components/api_key_form.tsx rename to packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index 488cd7b51632d..18636070a0705 100644 --- a/packages/kbn-search-api-keys/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -7,12 +7,13 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { useCallback, useState } from 'react'; +import React, { useState } from 'react'; import { EuiBadge, EuiButton, EuiButtonIcon, EuiCode, + EuiCopy, EuiFlexGroup, EuiFlexItem, EuiTitle, @@ -27,10 +28,6 @@ export const ApiKeyForm = () => { const { euiTheme } = useEuiTheme(); const [showFlyout, setShowFlyout] = useState(false); const { apiKey, status, handleSaveKey, showAPIKey, displayedApiKey } = useSearchApiKey(); - const handleAddToClipboard = useCallback( - () => apiKey && navigator.clipboard.writeText(apiKey), - [apiKey] - ); return ( @@ -73,17 +70,27 @@ export const ApiKeyForm = () => { })} /> - - - + {apiKey && ( + + + {(copy) => ( + + )} + + + )} )} {status === Status.showCreateButton && ( @@ -102,7 +109,7 @@ export const ApiKeyForm = () => { /> {showFlyout && ( - setShowFlyout(false)} onSuccess={handleSaveKey} /> + setShowFlyout(false)} onSuccess={handleSaveKey} /> )} )} diff --git a/packages/kbn-search-api-keys/hooks/use_search_api_key.ts b/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts similarity index 97% rename from packages/kbn-search-api-keys/hooks/use_search_api_key.ts rename to packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts index 49b99562ed7f8..00c0573bba3ff 100644 --- a/packages/kbn-search-api-keys/hooks/use_search_api_key.ts +++ b/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts @@ -10,8 +10,8 @@ import { useEffect, useCallback, useReducer } from 'react'; import { useMutation } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { APIKeyCreationResponse } from '../common/types'; -import { APIRoutes } from '../common/types'; +import type { APIKeyCreationResponse } from '@kbn/search-api-keys-api/types'; +import { APIRoutes } from '../../types'; const API_KEY_STORAGE_KEY = 'searchApiKey'; const API_KEY_MASK = '•'.repeat(60); diff --git a/packages/kbn-search-api-keys/common/index.ts b/packages/kbn-search-api-keys-components/public/index.ts similarity index 77% rename from packages/kbn-search-api-keys/common/index.ts rename to packages/kbn-search-api-keys-components/public/index.ts index be967ed8eb4eb..86cf4e4c49603 100644 --- a/packages/kbn-search-api-keys/common/index.ts +++ b/packages/kbn-search-api-keys-components/public/index.ts @@ -7,4 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export const API_KEY_NAME = 'Unrestricted API Key'; +export * from './components/api_key_flyout_wrapper'; +export * from './components/api_key_form'; +export * from './hooks/use_search_api_key'; diff --git a/packages/kbn-search-api-keys/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json similarity index 89% rename from packages/kbn-search-api-keys/tsconfig.json rename to packages/kbn-search-api-keys-components/tsconfig.json index 11e85314f249c..f47c4d4c6188a 100644 --- a/packages/kbn-search-api-keys/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -4,9 +4,8 @@ "outDir": "target/types", }, "include": [ - "common/**/*", - "public/**/*", - "server/**/*", + "public/components/**/*", + "public/hooks/**/*" ], "kbn_references": [ "@kbn/config-schema", diff --git a/packages/kbn-search-api-keys-components/types.ts b/packages/kbn-search-api-keys-components/types.ts new file mode 100644 index 0000000000000..146b5fdd2faca --- /dev/null +++ b/packages/kbn-search-api-keys-components/types.ts @@ -0,0 +1,13 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export enum APIRoutes { + API_KEYS = '/internal/search_api_keys', + API_KEY_VALIDITY = '/internal/search_api_keys/validity', +} diff --git a/packages/kbn-search-api-keys/hooks/use_current_user.ts b/packages/kbn-search-api-keys/hooks/use_current_user.ts deleted file mode 100644 index 06b719adea806..0000000000000 --- a/packages/kbn-search-api-keys/hooks/use_current_user.ts +++ /dev/null @@ -1,31 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useState, useEffect } from 'react'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { AuthenticatedUser } from '@kbn/core-security-common'; - -export const useCurrentUser = () => { - const { security } = useKibana().services; - const [user, setUser] = useState(undefined); - - useEffect(() => { - const getCurrentUser = async () => { - try { - const authenticatedUser = await security!.authc.getCurrentUser(); - setUser(authenticatedUser); - } catch { - setUser(undefined); - } - }; - getCurrentUser(); - }, [security]); - - return user; -}; diff --git a/packages/kbn-search-api-keys/kibana.jsonc b/packages/kbn-search-api-keys/kibana.jsonc deleted file mode 100644 index ad8fd270238ae..0000000000000 --- a/packages/kbn-search-api-keys/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/search-api-keys", - "owner": "@elastic/search-kibana" -} \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index b9526fbc04a0c..e9bd41d5df593 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1498,8 +1498,10 @@ "@kbn/screenshotting-plugin/*": ["x-pack/plugins/screenshotting/*"], "@kbn/screenshotting-server": ["packages/kbn-screenshotting-server"], "@kbn/screenshotting-server/*": ["packages/kbn-screenshotting-server/*"], - "@kbn/search-api-keys": ["packages/kbn-search-api-keys"], - "@kbn/search-api-keys/*": ["packages/kbn-search-api-keys/*"], + "@kbn/search-api-keys-api": ["packages/kbn-search-api-keys-api"], + "@kbn/search-api-keys-api/*": ["packages/kbn-search-api-keys-api/*"], + "@kbn/search-api-keys-components": ["packages/kbn-search-api-keys-components"], + "@kbn/search-api-keys-components/*": ["packages/kbn-search-api-keys-components/*"], "@kbn/search-api-panels": ["packages/kbn-search-api-panels"], "@kbn/search-api-panels/*": ["packages/kbn-search-api-panels/*"], "@kbn/search-assistant": ["x-pack/plugins/search_assistant"], diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx index 2e79175cd076b..91626d91f8577 100644 --- a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx @@ -26,7 +26,7 @@ import { useParams } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; -import { ApiKeyForm } from '@kbn/search-api-keys/components/api_key_form'; +import { ApiKeyForm } from '@kbn/search-api-keys-components/public'; import { useIndex } from '../../hooks/api/use_index'; import { useKibana } from '../../hooks/use_kibana'; import { ConnectionDetails } from '../connection_details/connection_details'; diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx index 8c23530a6b07e..5e7b2ee73b9c6 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx @@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; -import { ApiKeyForm } from '@kbn/search-api-keys/components/api_key_form'; +import { ApiKeyForm } from '@kbn/search-api-keys-components/public'; import { AnalyticsEvents } from '../../analytics/constants'; import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples'; import { DenseVectorSeverlessCodeExamples } from '../../code_examples/create_index'; diff --git a/x-pack/plugins/search_indices/server/routes/index.ts b/x-pack/plugins/search_indices/server/routes/index.ts index 222c4dc4a2311..fa954fff119c6 100644 --- a/x-pack/plugins/search_indices/server/routes/index.ts +++ b/x-pack/plugins/search_indices/server/routes/index.ts @@ -8,7 +8,7 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; -import { registerSearchApiKeysRoutes } from '@kbn/search-api-keys/server/routes/routes'; +import { registerSearchApiKeysRoutes } from '@kbn/search-api-keys-api/server/routes/routes'; import { registerIndicesRoutes } from './indices'; import { registerStatusRoutes } from './status'; diff --git a/yarn.lock b/yarn.lock index 5738d08f658b8..40f2b277b3403 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6267,7 +6267,11 @@ version "0.0.0" uid "" -"@kbn/search-api-keys@link:packages/kbn-search-api-keys": +"@kbn/search-api-keys-api@link:packages/kbn-search-api-keys-api": + version "0.0.0" + uid "" + +"@kbn/search-api-keys-components@link:packages/kbn-search-api-keys-components": version "0.0.0" uid "" From 4d962fe93c8e877a49e5facbe901f9ac2f136064 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 27 Sep 2024 13:46:51 +0100 Subject: [PATCH 19/36] updates to package move --- .github/CODEOWNERS | 3 ++- .i18nrc.json | 1 + .../public/components/api_key_form.tsx | 12 ++++++------ .../kbn-search-api-keys-components/tsconfig.json | 4 ---- x-pack/.i18nrc.json | 1 - 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0cf36b5d82788..a09afecdf8545 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -752,7 +752,8 @@ src/plugins/screenshot_mode @elastic/appex-sharedux x-pack/examples/screenshotting_example @elastic/appex-sharedux x-pack/plugins/screenshotting @elastic/kibana-reporting-services packages/kbn-screenshotting-server @elastic/appex-sharedux -x-pack/plugins/search_api_keys @elastic/search-kibana +packages/kbn-search-api-keys-components @elastic/search-kibana +packages/kbn-search-api-keys-api @elastic/search-kibana packages/kbn-search-api-panels @elastic/search-kibana x-pack/plugins/search_assistant @elastic/search-kibana packages/kbn-search-connectors @elastic/search-kibana diff --git a/.i18nrc.json b/.i18nrc.json index e9500448b9a09..036be597ac969 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -109,6 +109,7 @@ "server": "src/legacy/server", "share": ["src/plugins/share", "packages/kbn-reporting-share"], "sharedUXPackages": "packages/shared-ux", + "searchApiKeysComponents": "packages/kbn-search-api-keys-components", "searchApiPanels": "packages/kbn-search-api-panels/", "searchErrors": "packages/kbn-search-errors", "searchIndexDocuments": "packages/kbn-search-index-documents", diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index 18636070a0705..aadcefd97f0fc 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -34,14 +34,14 @@ export const ApiKeyForm = () => {
- +
{status === Status.showUserPrivilegesError && ( - {i18n.translate('xpack.searchApiKeys.apiKeyForm.noUserPrivileges', { + {i18n.translate('searchApiKeysComponents.apiKeyForm.noUserPrivileges', { defaultMessage: "You don't have access to manage API keys", })} @@ -65,7 +65,7 @@ export const ApiKeyForm = () => { color="success" onClick={showAPIKey} data-test-subj="showAPIKeyButton" - aria-label={i18n.translate('xpack.searchApiKeys.apiKeyForm.showApiKey', { + aria-label={i18n.translate('searchApiKeysComponents.apiKeyForm.showApiKey', { defaultMessage: 'Show API Key', })} /> @@ -74,7 +74,7 @@ export const ApiKeyForm = () => { @@ -83,7 +83,7 @@ export const ApiKeyForm = () => { onClick={copy} iconType="copy" color="success" - aria-label={i18n.translate('xpack.searchApiKeys.apiKeyForm.copyMessageLabel', { + aria-label={i18n.translate('searchApiKeysComponents.apiKeyForm.copyMessageLabel', { defaultMessage: 'Copy Elasticsearch URL to clipboard', })} /> @@ -104,7 +104,7 @@ export const ApiKeyForm = () => { data-test-subj="createAPIKeyButton" > diff --git a/packages/kbn-search-api-keys-components/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json index f47c4d4c6188a..5179f73f44709 100644 --- a/packages/kbn-search-api-keys-components/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -8,14 +8,10 @@ "public/hooks/**/*" ], "kbn_references": [ - "@kbn/config-schema", "@kbn/core", - "@kbn/core-elasticsearch-server", "@kbn/i18n", "@kbn/i18n-react", "@kbn/kibana-react-plugin", - "@kbn/navigation-plugin", - "@kbn/logging", "@kbn/security-api-key-management", "@kbn/core-security-common" ], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index d4b63420d6870..97aa05deb4a42 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -106,7 +106,6 @@ "xpack.screenshotting": "plugins/screenshotting", "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchIndices": "plugins/search_indices", - "xpack.searchApiKeys": "packages/search-api-keys", "xpack.searchNotebooks": "plugins/search_notebooks", "xpack.searchPlayground": "plugins/search_playground", "xpack.searchInferenceEndpoints": "plugins/search_inference_endpoints", From 7ea3563637456b0846c20dde149735de359cebfc Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 27 Sep 2024 13:47:58 +0100 Subject: [PATCH 20/36] fix prettier --- .../public/components/api_key_form.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index aadcefd97f0fc..6278c11d1d465 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -34,7 +34,10 @@ export const ApiKeyForm = () => {
- +
@@ -83,9 +86,12 @@ export const ApiKeyForm = () => { onClick={copy} iconType="copy" color="success" - aria-label={i18n.translate('searchApiKeysComponents.apiKeyForm.copyMessageLabel', { - defaultMessage: 'Copy Elasticsearch URL to clipboard', - })} + aria-label={i18n.translate( + 'searchApiKeysComponents.apiKeyForm.copyMessageLabel', + { + defaultMessage: 'Copy Elasticsearch URL to clipboard', + } + )} /> )}
From 3c25c837972e2c5bb70a69af6b5ffc608b69ad0e Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 27 Sep 2024 15:44:07 +0100 Subject: [PATCH 21/36] update api form design --- .../public/components/api_key_form.tsx | 19 +++-- .../connection_details/connection_details.tsx | 12 +++ .../form_info_field/form_info_field.tsx | 85 +++++++++++++++++++ 3 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index 6278c11d1d465..9b42128d182c3 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -12,7 +12,6 @@ import { EuiBadge, EuiButton, EuiButtonIcon, - EuiCode, EuiCopy, EuiFlexGroup, EuiFlexItem, @@ -52,15 +51,21 @@ export const ApiKeyForm = () => { )} {status !== Status.showCreateButton && ( <> - - + {displayedApiKey} - + { const { euiTheme } = useEuiTheme(); const elasticsearchUrl = useElasticsearchUrl(); + return ( + + ); + return ( diff --git a/x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx b/x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx new file mode 100644 index 0000000000000..a0fa43576b276 --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx @@ -0,0 +1,85 @@ +/* + * 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'; + +import { + EuiButtonIcon, + EuiCopy, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + useEuiTheme, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +interface FormInfoFieldProps { + actions?: React.ReactNode[]; + label: string; + value: string; + copyValue?: string; + dataTestSubj?: string; +} + +export const FormInfoField: React.FC = ({ + actions = [], + label, + value, + copyValue, + dataTestSubj, +}) => { + const { euiTheme } = useEuiTheme(); + + return ( + + + +

{label}

+
+
+ + + {value} + + + + + {(copy) => ( + + )} + + + {actions.map((action, index) => ( + + {action} + + ))} +
+ ); +}; From 65a8d4e624df144738905399722a967bdab66bb4 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 27 Sep 2024 21:02:14 +0100 Subject: [PATCH 22/36] add form field --- .github/CODEOWNERS | 1 + package.json | 1 + .../public/components/api_key_form.tsx | 109 +++++++----------- tsconfig.base.json | 2 + x-pack/.i18nrc.json | 1 + x-pack/packages/search/shared_ui/README.md | 3 + x-pack/packages/search/shared_ui/index.ts | 8 ++ .../packages/search/shared_ui/jest.config.js | 15 +++ x-pack/packages/search/shared_ui/kibana.jsonc | 5 + x-pack/packages/search/shared_ui/package.json | 6 + .../src}/form_info_field/form_info_field.tsx | 19 +-- .../packages/search/shared_ui/tsconfig.json | 23 ++++ .../connection_details/connection_details.tsx | 59 +--------- .../components/start/create_index_code.tsx | 34 +++++- yarn.lock | 4 + 15 files changed, 148 insertions(+), 142 deletions(-) create mode 100644 x-pack/packages/search/shared_ui/README.md create mode 100644 x-pack/packages/search/shared_ui/index.ts create mode 100644 x-pack/packages/search/shared_ui/jest.config.js create mode 100644 x-pack/packages/search/shared_ui/kibana.jsonc create mode 100644 x-pack/packages/search/shared_ui/package.json rename x-pack/{plugins/search_indices/public/components => packages/search/shared_ui/src}/form_info_field/form_info_field.tsx (82%) create mode 100644 x-pack/packages/search/shared_ui/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a09afecdf8545..fe83c3c7b28ac 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -766,6 +766,7 @@ x-pack/plugins/search_indices @elastic/search-kibana x-pack/plugins/search_inference_endpoints @elastic/search-kibana x-pack/plugins/search_notebooks @elastic/search-kibana x-pack/plugins/search_playground @elastic/search-kibana +x-pack/packages/search/shared_ui @elastic/search-kibana packages/kbn-search-response-warnings @elastic/kibana-data-discovery packages/kbn-search-types @elastic/kibana-data-discovery x-pack/plugins/searchprofiler @elastic/kibana-management diff --git a/package.json b/package.json index 7a7dda7edcf31..9931ed791f1c6 100644 --- a/package.json +++ b/package.json @@ -784,6 +784,7 @@ "@kbn/search-notebooks": "link:x-pack/plugins/search_notebooks", "@kbn/search-playground": "link:x-pack/plugins/search_playground", "@kbn/search-response-warnings": "link:packages/kbn-search-response-warnings", + "@kbn/search-shared-ui": "link:x-pack/packages/search/shared_ui", "@kbn/search-types": "link:packages/kbn-search-types", "@kbn/searchprofiler-plugin": "link:x-pack/plugins/searchprofiler", "@kbn/security-api-key-management": "link:x-pack/packages/security/api_key_management", diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index 9b42128d182c3..e435322f4e32f 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -12,34 +12,58 @@ import { EuiBadge, EuiButton, EuiButtonIcon, - EuiCopy, EuiFlexGroup, EuiFlexItem, EuiTitle, - useEuiTheme, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { FormInfoField } from '@kbn/search-shared-ui'; import { ApiKeyFlyoutWrapper } from './api_key_flyout_wrapper'; import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; -export const ApiKeyForm = () => { - const { euiTheme } = useEuiTheme(); +interface ApiKeyFormProps { + hasTitle?: boolean; +} + +export const ApiKeyForm: React.FC = ({ hasTitle = true }) => { const [showFlyout, setShowFlyout] = useState(false); const { apiKey, status, handleSaveKey, showAPIKey, displayedApiKey } = useSearchApiKey(); + const titleLocale = i18n.translate('searchApiKeysComponents.apiKeyForm.title', { + defaultMessage: 'API Key', + }); + + if (apiKey && displayedApiKey) { + return ( + , + ]} + /> + ); + } + return ( - - -
- -
-
-
+ {hasTitle && ( + + +
{titleLocale}
+
+
+ )} {status === Status.showUserPrivilegesError && ( @@ -49,65 +73,10 @@ export const ApiKeyForm = () => { )} - {status !== Status.showCreateButton && ( - <> - - - {displayedApiKey} - - - - - - {apiKey && ( - - - {(copy) => ( - - )} - - - )} - - )} {status === Status.showCreateButton && ( /target/kibana-coverage/jest/x-pack/packages/search/shared_ui', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/x-pack/packages/search/shared_ui/**/*.{ts,tsx}'], + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/search/shared_ui'], +}; diff --git a/x-pack/packages/search/shared_ui/kibana.jsonc b/x-pack/packages/search/shared_ui/kibana.jsonc new file mode 100644 index 0000000000000..aedc015c1d6fa --- /dev/null +++ b/x-pack/packages/search/shared_ui/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/search-shared-ui", + "owner": "@elastic/search-kibana" +} \ No newline at end of file diff --git a/x-pack/packages/search/shared_ui/package.json b/x-pack/packages/search/shared_ui/package.json new file mode 100644 index 0000000000000..d1456579cd050 --- /dev/null +++ b/x-pack/packages/search/shared_ui/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/search-shared-ui", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx b/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx similarity index 82% rename from x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx rename to x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx index a0fa43576b276..5eeb739122ab8 100644 --- a/x-pack/plugins/search_indices/public/components/form_info_field/form_info_field.tsx +++ b/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; interface FormInfoFieldProps { actions?: React.ReactNode[]; - label: string; + label?: string; value: string; copyValue?: string; dataTestSubj?: string; @@ -36,11 +36,13 @@ export const FormInfoField: React.FC = ({ return ( - - -

{label}

-
-
+ {label && ( + + +

{label}

+
+
+ )} = ({ overflow: 'hidden', borderRadius: euiTheme.border.radius.small, fontWeight: euiTheme.font.weight.bold, + fontSize: euiTheme.size.m, }} > {value} @@ -60,7 +63,7 @@ export const FormInfoField: React.FC = ({ @@ -68,7 +71,7 @@ export const FormInfoField: React.FC = ({ diff --git a/x-pack/packages/search/shared_ui/tsconfig.json b/x-pack/packages/search/shared_ui/tsconfig.json new file mode 100644 index 0000000000000..915b8e1184d31 --- /dev/null +++ b/x-pack/packages/search/shared_ui/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/i18n-react", + "@kbn/i18n", + "@kbn/ui-theme", + ], +} \ No newline at end of file diff --git a/x-pack/plugins/search_indices/public/components/connection_details/connection_details.tsx b/x-pack/plugins/search_indices/public/components/connection_details/connection_details.tsx index e1e4ceebbde6a..b79a0e1f16828 100644 --- a/x-pack/plugins/search_indices/public/components/connection_details/connection_details.tsx +++ b/x-pack/plugins/search_indices/public/components/connection_details/connection_details.tsx @@ -7,22 +7,12 @@ import React from 'react'; -import { - EuiButtonIcon, - EuiCopy, - EuiFlexGroup, - EuiFlexItem, - EuiTitle, - useEuiTheme, -} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { FormInfoField } from '@kbn/search-shared-ui'; import { useElasticsearchUrl } from '../../hooks/use_elasticsearch_url'; -import { FormInfoField } from '../form_info_field/form_info_field'; export const ConnectionDetails: React.FC = () => { - const { euiTheme } = useEuiTheme(); const elasticsearchUrl = useElasticsearchUrl(); return ( @@ -35,51 +25,4 @@ export const ConnectionDetails: React.FC = () => { dataTestSubj="connectionDetailsEndpoint" /> ); - - return ( - - - -

- -

-
-
- -

- {elasticsearchUrl} -

-
- - - {(copy) => ( - - )} - - -
- ); }; diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx index 5e7b2ee73b9c6..51468fc7ecb87 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React, { useCallback, useMemo, useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; @@ -59,11 +59,33 @@ export const CreateIndexCodeView = ({ createIndexForm }: CreateIndexCodeViewProp return ( - - - - - + + + + + +
+ {i18n.translate('xpack.searchIndices.startPage.codeView.apiKeyTitle', { + defaultMessage: 'Copy your API key', + })} +
+
+
+ + +

+ {i18n.translate('xpack.searchIndices.startPage.codeView.apiKeyDescription', { + defaultMessage: + 'Make sure you keep it somewhere safe. You won’t be able to retrieve it later.', + })} +

+
+
+
+ + +
+
Date: Fri, 27 Sep 2024 20:17:12 +0000 Subject: [PATCH 23/36] [CI] Auto-commit changed files from 'node scripts/generate codeowners' --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fe83c3c7b28ac..074b79924d80b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -752,8 +752,8 @@ src/plugins/screenshot_mode @elastic/appex-sharedux x-pack/examples/screenshotting_example @elastic/appex-sharedux x-pack/plugins/screenshotting @elastic/kibana-reporting-services packages/kbn-screenshotting-server @elastic/appex-sharedux -packages/kbn-search-api-keys-components @elastic/search-kibana packages/kbn-search-api-keys-api @elastic/search-kibana +packages/kbn-search-api-keys-components @elastic/search-kibana packages/kbn-search-api-panels @elastic/search-kibana x-pack/plugins/search_assistant @elastic/search-kibana packages/kbn-search-connectors @elastic/search-kibana @@ -766,8 +766,8 @@ x-pack/plugins/search_indices @elastic/search-kibana x-pack/plugins/search_inference_endpoints @elastic/search-kibana x-pack/plugins/search_notebooks @elastic/search-kibana x-pack/plugins/search_playground @elastic/search-kibana -x-pack/packages/search/shared_ui @elastic/search-kibana packages/kbn-search-response-warnings @elastic/kibana-data-discovery +x-pack/packages/search/shared_ui @elastic/search-kibana packages/kbn-search-types @elastic/kibana-data-discovery x-pack/plugins/searchprofiler @elastic/kibana-management x-pack/test/security_api_integration/packages/helpers @elastic/kibana-security From 074e9a12063e3d2441f2ccd1e28c77b070d28c68 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 27 Sep 2024 20:29:05 +0000 Subject: [PATCH 24/36] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-search-api-keys-api/tsconfig.json | 9 +++++++-- packages/kbn-search-api-keys-components/tsconfig.json | 6 +++--- x-pack/packages/search/shared_ui/tsconfig.json | 4 +--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/kbn-search-api-keys-api/tsconfig.json b/packages/kbn-search-api-keys-api/tsconfig.json index 6ee9003bd7e75..bd6432a81c31b 100644 --- a/packages/kbn-search-api-keys-api/tsconfig.json +++ b/packages/kbn-search-api-keys-api/tsconfig.json @@ -6,8 +6,13 @@ "include": [ "server/**/*", ], - "kbn_references": [], + "kbn_references": [ + "@kbn/core-elasticsearch-server", + "@kbn/logging", + "@kbn/core", + "@kbn/config-schema", + ], "exclude": [ "target/**/*", ] -} \ No newline at end of file +} diff --git a/packages/kbn-search-api-keys-components/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json index 5179f73f44709..4d7729d793997 100644 --- a/packages/kbn-search-api-keys-components/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -8,14 +8,14 @@ "public/hooks/**/*" ], "kbn_references": [ - "@kbn/core", "@kbn/i18n", "@kbn/i18n-react", "@kbn/kibana-react-plugin", "@kbn/security-api-key-management", - "@kbn/core-security-common" + "@kbn/search-shared-ui", + "@kbn/search-api-keys-api" ], "exclude": [ "target/**/*", ] -} \ No newline at end of file +} diff --git a/x-pack/packages/search/shared_ui/tsconfig.json b/x-pack/packages/search/shared_ui/tsconfig.json index 915b8e1184d31..21d23f459ef7a 100644 --- a/x-pack/packages/search/shared_ui/tsconfig.json +++ b/x-pack/packages/search/shared_ui/tsconfig.json @@ -16,8 +16,6 @@ "target/**/*" ], "kbn_references": [ - "@kbn/i18n-react", "@kbn/i18n", - "@kbn/ui-theme", ], -} \ No newline at end of file +} From e281ce3209c3934b85dd82da3a47e9124a6c114d Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 30 Sep 2024 10:40:41 +0100 Subject: [PATCH 25/36] fix ts issues --- packages/kbn-search-api-keys-api/server/index.ts | 10 ++++++++++ .../kbn-search-api-keys-api/server/lib/create_key.ts | 2 +- .../server/lib/get_key_by_id.ts | 2 +- .../kbn-search-api-keys-api/server/routes/routes.ts | 2 +- packages/kbn-search-api-keys-api/{ => server}/types.ts | 0 packages/kbn-search-api-keys-api/tsconfig.json | 6 ++++-- .../public/components/api_key_flyout_wrapper.tsx | 2 +- .../public/hooks/use_search_api_key.ts | 4 ++-- .../{ => public}/types.ts | 0 packages/kbn-search-api-keys-components/tsconfig.json | 7 ++++--- .../shared_ui/src/form_info_field/form_info_field.tsx | 2 +- x-pack/packages/search/shared_ui/tsconfig.json | 1 + x-pack/plugins/search_indices/server/routes/index.ts | 2 +- x-pack/plugins/search_indices/tsconfig.json | 5 +++-- 14 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 packages/kbn-search-api-keys-api/server/index.ts rename packages/kbn-search-api-keys-api/{ => server}/types.ts (100%) rename packages/kbn-search-api-keys-components/{ => public}/types.ts (100%) diff --git a/packages/kbn-search-api-keys-api/server/index.ts b/packages/kbn-search-api-keys-api/server/index.ts new file mode 100644 index 0000000000000..67646efc2e8fb --- /dev/null +++ b/packages/kbn-search-api-keys-api/server/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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export * from './routes/routes'; diff --git a/packages/kbn-search-api-keys-api/server/lib/create_key.ts b/packages/kbn-search-api-keys-api/server/lib/create_key.ts index 7bebe713810c8..e74605c32440d 100644 --- a/packages/kbn-search-api-keys-api/server/lib/create_key.ts +++ b/packages/kbn-search-api-keys-api/server/lib/create_key.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; -import type { APIKeyCreationResponse } from '../../types'; +import type { APIKeyCreationResponse } from '../types'; export async function createAPIKey( name: string, diff --git a/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts b/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts index 94ae64f56c0da..a1337de4c4981 100644 --- a/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts +++ b/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; -import type { GetApiKeyResponse } from '../../types'; +import type { GetApiKeyResponse } from '../types'; export async function getAPIKeyById( id: string, diff --git a/packages/kbn-search-api-keys-api/server/routes/routes.ts b/packages/kbn-search-api-keys-api/server/routes/routes.ts index 77a08644f34a5..d3ddd4c4e21f1 100644 --- a/packages/kbn-search-api-keys-api/server/routes/routes.ts +++ b/packages/kbn-search-api-keys-api/server/routes/routes.ts @@ -11,7 +11,7 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import { schema } from '@kbn/config-schema'; -import { APIRoutes } from '../../types'; +import { APIRoutes } from '../types'; import { getAPIKeyById } from '../lib/get_key_by_id'; import { createAPIKey } from '../lib/create_key'; import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; diff --git a/packages/kbn-search-api-keys-api/types.ts b/packages/kbn-search-api-keys-api/server/types.ts similarity index 100% rename from packages/kbn-search-api-keys-api/types.ts rename to packages/kbn-search-api-keys-api/server/types.ts diff --git a/packages/kbn-search-api-keys-api/tsconfig.json b/packages/kbn-search-api-keys-api/tsconfig.json index 6ee9003bd7e75..f2c8275f46cf7 100644 --- a/packages/kbn-search-api-keys-api/tsconfig.json +++ b/packages/kbn-search-api-keys-api/tsconfig.json @@ -4,9 +4,11 @@ "outDir": "target/types", }, "include": [ - "server/**/*", + "server/**/*" + ], + "kbn_references": [ + "@kbn/core", ], - "kbn_references": [], "exclude": [ "target/**/*", ] diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx index 6eaab8d0865ed..35db216df1ef3 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx @@ -7,8 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ApiKeyFlyout, ApiKeyFlyoutProps } from '@kbn/security-api-key-management'; import React from 'react'; +import { ApiKeyFlyout, ApiKeyFlyoutProps } from '@kbn/security-api-key-management'; import type { SecurityCreateApiKeyResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; const API_KEY_NAME = 'Unrestricted API Key'; diff --git a/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts b/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts index 00c0573bba3ff..60af6bd5f92a5 100644 --- a/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts +++ b/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts @@ -10,8 +10,8 @@ import { useEffect, useCallback, useReducer } from 'react'; import { useMutation } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { APIKeyCreationResponse } from '@kbn/search-api-keys-api/types'; -import { APIRoutes } from '../../types'; +import type { APIKeyCreationResponse } from '@kbn/search-api-keys-api/server/types'; +import { APIRoutes } from '../types'; const API_KEY_STORAGE_KEY = 'searchApiKey'; const API_KEY_MASK = '•'.repeat(60); diff --git a/packages/kbn-search-api-keys-components/types.ts b/packages/kbn-search-api-keys-components/public/types.ts similarity index 100% rename from packages/kbn-search-api-keys-components/types.ts rename to packages/kbn-search-api-keys-components/public/types.ts diff --git a/packages/kbn-search-api-keys-components/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json index 5179f73f44709..77d37015ea70b 100644 --- a/packages/kbn-search-api-keys-components/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -4,8 +4,7 @@ "outDir": "target/types", }, "include": [ - "public/components/**/*", - "public/hooks/**/*" + "public/**/*", ], "kbn_references": [ "@kbn/core", @@ -13,7 +12,9 @@ "@kbn/i18n-react", "@kbn/kibana-react-plugin", "@kbn/security-api-key-management", - "@kbn/core-security-common" + "@kbn/core-security-common", + "@kbn/search-shared-ui", + "@kbn/search-api-keys-api", ], "exclude": [ "target/**/*", diff --git a/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx b/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx index 5eeb739122ab8..bf33143dcc3ba 100644 --- a/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx +++ b/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx @@ -46,7 +46,7 @@ export const FormInfoField: React.FC = ({ Date: Mon, 30 Sep 2024 10:58:45 +0100 Subject: [PATCH 26/36] fix i18n issues --- x-pack/.i18nrc.json | 2 +- .../search/shared_ui/src/form_info_field/form_info_field.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 7c53a031a9978..72e35fb16de2f 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -104,7 +104,7 @@ "xpack.rollupJobs": ["packages/rollup", "plugins/rollup"], "xpack.runtimeFields": "plugins/runtime_fields", "xpack.screenshotting": "plugins/screenshotting", - "xpack.search.sharedui": "x-pack/packages/search/shared_ui", + "xpack.searchSharedUI": "packages/search/shared_ui", "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchIndices": "plugins/search_indices", "xpack.searchNotebooks": "plugins/search_notebooks", diff --git a/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx b/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx index bf33143dcc3ba..89e14e72454c6 100644 --- a/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx +++ b/x-pack/packages/search/shared_ui/src/form_info_field/form_info_field.tsx @@ -63,7 +63,7 @@ export const FormInfoField: React.FC = ({ @@ -71,7 +71,7 @@ export const FormInfoField: React.FC = ({ From c93db2d05d2a64f37db8fc6af53038e48f4a6552 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:14:02 +0000 Subject: [PATCH 27/36] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-search-api-keys-api/tsconfig.json | 2 +- packages/kbn-search-api-keys-components/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-search-api-keys-api/tsconfig.json b/packages/kbn-search-api-keys-api/tsconfig.json index 212e6a8041e23..b775a5eee6418 100644 --- a/packages/kbn-search-api-keys-api/tsconfig.json +++ b/packages/kbn-search-api-keys-api/tsconfig.json @@ -15,4 +15,4 @@ "exclude": [ "target/**/*", ] -} \ No newline at end of file +} diff --git a/packages/kbn-search-api-keys-components/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json index b4265857a8446..ec779956b1547 100644 --- a/packages/kbn-search-api-keys-components/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -17,4 +17,4 @@ "exclude": [ "target/**/*", ] -} \ No newline at end of file +} From 265379cb5806859b5ea225b4f1a5593b49cb0d81 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:31:27 +0000 Subject: [PATCH 28/36] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/plugins/search_indices/tsconfig.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index f2ef644865946..ca6763a6a8563 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -35,9 +35,10 @@ "@kbn/search-index-documents", "@kbn/es-types", "@kbn/search-api-keys-api", - "@kbn/search-api-keys-components" + "@kbn/search-api-keys-components", + "@kbn/search-shared-ui" ], "exclude": [ "target/**/*", ] -} \ No newline at end of file +} From bb5fa80a975e7975e7b551e417158c0c7c4c3162 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 30 Sep 2024 12:11:13 +0100 Subject: [PATCH 29/36] fix jest configs --- packages/kbn-search-api-keys-api/jest.config.js | 6 +++--- packages/kbn-search-api-keys-components/jest.config.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kbn-search-api-keys-api/jest.config.js b/packages/kbn-search-api-keys-api/jest.config.js index 695232991aaee..997b5ed138a01 100644 --- a/packages/kbn-search-api-keys-api/jest.config.js +++ b/packages/kbn-search-api-keys-api/jest.config.js @@ -8,10 +8,10 @@ */ module.exports = { - preset: '@kbn/test', - rootDir: '../../..', + preset: '@kbn/test/jest_node', + rootDir: '../..', roots: ['/packages/kbn-search-api-keys-api'], coverageDirectory: '/target/kibana-coverage/jest/packages/kbn-search-api-keys-api', coverageReporters: ['text', 'html'], - collectCoverageFrom: ['/packages/kbn-search-api-keys-api/{server}/**/*.{ts,tsx}'], + collectCoverageFrom: ['/packages/kbn-search-api-keys-api/**/*.{ts,tsx}'], }; diff --git a/packages/kbn-search-api-keys-components/jest.config.js b/packages/kbn-search-api-keys-components/jest.config.js index f6c992d97de10..d1868067bb31c 100644 --- a/packages/kbn-search-api-keys-components/jest.config.js +++ b/packages/kbn-search-api-keys-components/jest.config.js @@ -9,7 +9,7 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../..', + rootDir: '../..', roots: ['/packages/kbn-search-api-keys-components'], coverageDirectory: '/target/kibana-coverage/jest/packages/kbn-search-api-keys-components', From dc203dde9f374a3c2ca5f4a1da565f8a211d1e1b Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 30 Sep 2024 13:45:22 +0100 Subject: [PATCH 30/36] update ftrs --- .../public/components/api_key_form.tsx | 1 + .../functional/test_suites/search/index.feature_flags.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index e435322f4e32f..5bbca0684f81f 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -40,6 +40,7 @@ export const ApiKeyForm: React.FC = ({ hasTitle = true }) => { label={hasTitle ? titleLocale : undefined} value={displayedApiKey} copyValue={apiKey} + dataTestSubj="apiKeyFormAPIKey" actions={[ Date: Mon, 30 Sep 2024 13:47:14 +0100 Subject: [PATCH 31/36] update readme --- packages/kbn-search-api-keys-components/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-search-api-keys-components/README.md b/packages/kbn-search-api-keys-components/README.md index 82a42ad81b5b6..06815bf556f00 100644 --- a/packages/kbn-search-api-keys-components/README.md +++ b/packages/kbn-search-api-keys-components/README.md @@ -1,3 +1,3 @@ -# Search API Keys +# Search API Key Components -The Search API Keys package is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. \ No newline at end of file +The Search API Keys components package is a shared components and utilities to simplify managing the API Keys experience for elasticsearch users across stack and serverless search solutions. \ No newline at end of file From fcf24f3c180531eaf644a40d2f5bb91e53b60377 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 30 Sep 2024 20:08:19 +0100 Subject: [PATCH 32/36] fix typo --- .../test_suites/search/elasticsearch_start.ts | 91 ++++++++++--------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts index 0eee7fcdc9a9e..aecfe217ba933 100644 --- a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts +++ b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts @@ -133,51 +133,52 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const indexDetailsApiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); expect(apiKeyUI).to.eql(indexDetailsApiKey); - it('should have file upload link', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.clickFileUploadLink(); - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnMLFileUploadPage(); - }); - - it('should have o11y links', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.expectAnalyzeLogsLink(); - await pageObjects.svlSearchElasticsearchStartPage.expectO11yTrialLink(); - }); - }); - describe('viewer', function () { - before(async () => { - await pageObjects.svlCommonPage.loginAsViewer(); - await deleteAllTestIndices(); - }); - beforeEach(async () => { - await svlSearchNavigation.navigateToElasticsearchStartPage(); - }); - after(async () => { - await deleteAllTestIndices(); - }); - - it('should default to code view when lacking create index permissions', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexCodeView(); - await pageObjects.svlSearchElasticsearchStartPage.clickUIViewButton(); - await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexUIView(); - await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexButtonToBeDisabled(); - }); - - it('should not create an API key if the user only has viewer permissions', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); - await pageObjects.svlApiKeys.expectNoPermissionsMessage(); - const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromSessionStorage(); - expect(apiKey).to.be(null); - }); - - it('should redirect to index details when index is created via API', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexCodeView(); - await es.indices.create({ index: 'test-my-api-index' }); - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnIndexDetailsPage(); + it('should have file upload link', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.clickFileUploadLink(); + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnMLFileUploadPage(); + }); + + it('should have o11y links', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.expectAnalyzeLogsLink(); + await pageObjects.svlSearchElasticsearchStartPage.expectO11yTrialLink(); + }); + }); + describe('viewer', function () { + before(async () => { + await pageObjects.svlCommonPage.loginAsViewer(); + await deleteAllTestIndices(); + }); + beforeEach(async () => { + await svlSearchNavigation.navigateToElasticsearchStartPage(); + }); + after(async () => { + await deleteAllTestIndices(); + }); + + it('should default to code view when lacking create index permissions', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexCodeView(); + await pageObjects.svlSearchElasticsearchStartPage.clickUIViewButton(); + await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexUIView(); + await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexButtonToBeDisabled(); + }); + + it('should not create an API key if the user only has viewer permissions', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); + await pageObjects.svlApiKeys.expectNoPermissionsMessage(); + const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromSessionStorage(); + expect(apiKey).to.be(null); + }); + + it('should redirect to index details when index is created via API', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexCodeView(); + await es.indices.create({ index: 'test-my-api-index' }); + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnIndexDetailsPage(); + }); }); }); }); From 3ce5e0bed4f4a290d8640020f489c7c18bc375c9 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Tue, 1 Oct 2024 13:48:29 +0100 Subject: [PATCH 33/36] added provider; toggle visibility of apiKey; implement code sample updating --- .../public/components/api_key_form.tsx | 12 +- .../public/constants.ts | 17 ++ .../public/hooks/use_search_api_key.ts | 143 +------------- .../public/index.ts | 1 + .../providers/search_api_key_provider.tsx | 182 ++++++++++++++++++ .../search_indices/public/application.tsx | 5 +- .../add_documents_code_example.tsx | 6 + .../public/components/shared/code_sample.tsx | 13 +- .../components/start/create_index_code.tsx | 5 +- .../svl_search_elasticsearch_start_page.ts | 6 + .../svl_search_index_detail_page.ts | 7 + .../test_suites/search/elasticsearch_start.ts | 25 ++- .../test_suites/search/search_index_detail.ts | 8 + 13 files changed, 274 insertions(+), 156 deletions(-) create mode 100644 packages/kbn-search-api-keys-components/public/constants.ts create mode 100644 packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx index 5bbca0684f81f..ccd169c413bb1 100644 --- a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx +++ b/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx @@ -20,7 +20,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { FormInfoField } from '@kbn/search-shared-ui'; import { ApiKeyFlyoutWrapper } from './api_key_flyout_wrapper'; -import { useSearchApiKey, Status } from '../hooks/use_search_api_key'; +import { useSearchApiKey } from '../hooks/use_search_api_key'; +import { Status } from '../constants'; interface ApiKeyFormProps { hasTitle?: boolean; @@ -28,7 +29,8 @@ interface ApiKeyFormProps { export const ApiKeyForm: React.FC = ({ hasTitle = true }) => { const [showFlyout, setShowFlyout] = useState(false); - const { apiKey, status, handleSaveKey, showAPIKey, displayedApiKey } = useSearchApiKey(); + const { apiKey, status, updateApiKey, toggleApiKeyVisibility, displayedApiKey, apiKeyIsVisible } = + useSearchApiKey(); const titleLocale = i18n.translate('searchApiKeysComponents.apiKeyForm.title', { defaultMessage: 'API Key', @@ -43,9 +45,9 @@ export const ApiKeyForm: React.FC = ({ hasTitle = true }) => { dataTestSubj="apiKeyFormAPIKey" actions={[ = ({ hasTitle = true }) => { />
{showFlyout && ( - setShowFlyout(false)} onSuccess={handleSaveKey} /> + setShowFlyout(false)} onSuccess={updateApiKey} /> )}
)} diff --git a/packages/kbn-search-api-keys-components/public/constants.ts b/packages/kbn-search-api-keys-components/public/constants.ts new file mode 100644 index 0000000000000..b822ccb042a70 --- /dev/null +++ b/packages/kbn-search-api-keys-components/public/constants.ts @@ -0,0 +1,17 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export enum Status { + uninitialized = 'uninitialized', + loading = 'loading', + showCreateButton = 'showCreateButton', + showHiddenKey = 'showHiddenKey', + showPreviewKey = 'showPreviewKey', + showUserPrivilegesError = 'showUserPrivilegesError', +} diff --git a/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts b/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts index 60af6bd5f92a5..9d0bd4826f9de 100644 --- a/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts +++ b/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts @@ -7,144 +7,13 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { useEffect, useCallback, useReducer } from 'react'; -import { useMutation } from '@tanstack/react-query'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { APIKeyCreationResponse } from '@kbn/search-api-keys-api/server/types'; -import { APIRoutes } from '../types'; - -const API_KEY_STORAGE_KEY = 'searchApiKey'; -const API_KEY_MASK = '•'.repeat(60); - -export enum Status { - loading = 'loading', - showCreateButton = 'showCreateButton', - showHiddenKey = 'showHiddenKey', - showPreviewKey = 'showPreviewKey', - showUserPrivilegesError = 'showUserPrivilegesError', -} - -interface ApiKeyState { - status: Status; - apiKey: string | null; -} - -type Action = - | { type: 'SET_API_KEY'; apiKey: string; status: Status } - | { type: 'SET_STATUS'; status: Status } - | { type: 'CLEAR_API_KEY' }; - -const initialState: ApiKeyState = { - apiKey: null, - status: Status.loading, -}; - -const reducer = (state: ApiKeyState, action: Action): ApiKeyState => { - switch (action.type) { - case 'SET_API_KEY': - return { ...state, apiKey: action.apiKey, status: action.status }; - case 'SET_STATUS': - return { ...state, status: action.status }; - case 'CLEAR_API_KEY': - return { ...state, apiKey: null, status: Status.showCreateButton }; - default: - return state; - } -}; +import { useContext, useEffect } from 'react'; +import { ApiKeyContext } from '../providers/search_api_key_provider'; export const useSearchApiKey = () => { - const { http } = useKibana().services; - const [state, dispatch] = useReducer(reducer, initialState); - const handleSaveKey = useCallback(({ id, encoded }: { id: string; encoded: string }) => { - sessionStorage.setItem(API_KEY_STORAGE_KEY, JSON.stringify({ id, encoded })); - dispatch({ type: 'SET_API_KEY', apiKey: encoded, status: Status.showHiddenKey }); - }, []); - const handleShowKeyVisibility = useCallback(() => { - dispatch({ type: 'SET_STATUS', status: Status.showPreviewKey }); - }, []); - const { mutateAsync: validateApiKey } = useMutation(async (id: string) => { - try { - if (!http?.post) { - throw new Error('HTTP service is unavailable'); - } - - const response = await http.post<{ isValid: boolean }>(APIRoutes.API_KEY_VALIDITY, { - body: JSON.stringify({ id }), - }); - - return response.isValid; - } catch (err) { - return false; - } - }); - const { mutateAsync: createApiKey } = useMutation({ - mutationFn: async () => { - try { - if (!http?.post) { - throw new Error('HTTP service is unavailable'); - } - - return await http.post(APIRoutes.API_KEYS); - } catch (err) { - if (err.response?.status === 400) { - dispatch({ type: 'SET_STATUS', status: Status.showCreateButton }); - } else if (err.response?.status === 403) { - dispatch({ type: 'SET_STATUS', status: Status.showUserPrivilegesError }); - } else { - throw err; - } - } - }, - onSuccess: (receivedApiKey) => { - if (receivedApiKey) { - sessionStorage.setItem( - API_KEY_STORAGE_KEY, - JSON.stringify({ id: receivedApiKey.id, encoded: receivedApiKey.encoded }) - ); - dispatch({ - type: 'SET_API_KEY', - apiKey: receivedApiKey.encoded, - status: Status.showHiddenKey, - }); - } - }, - }); - + const { initialiseKey, ...context } = useContext(ApiKeyContext); useEffect(() => { - (async () => { - try { - const storedKey = sessionStorage.getItem(API_KEY_STORAGE_KEY); - - if (storedKey) { - const { id, encoded } = JSON.parse(storedKey); - - if (await validateApiKey(id)) { - dispatch({ - type: 'SET_API_KEY', - apiKey: encoded, - status: Status.showHiddenKey, - }); - } else { - sessionStorage.removeItem(API_KEY_STORAGE_KEY); - dispatch({ - type: 'CLEAR_API_KEY', - }); - await createApiKey(); - } - } else { - await createApiKey(); - } - } catch (e) { - throw e; - } - })(); - }, [validateApiKey, createApiKey]); - - return { - displayedApiKey: state.status === Status.showHiddenKey ? API_KEY_MASK : state.apiKey, - apiKey: state.apiKey, - showAPIKey: handleShowKeyVisibility, - handleSaveKey, - status: state.status, - }; + initialiseKey(); + }, [initialiseKey]); + return context; }; diff --git a/packages/kbn-search-api-keys-components/public/index.ts b/packages/kbn-search-api-keys-components/public/index.ts index 86cf4e4c49603..3e3cb8e83a154 100644 --- a/packages/kbn-search-api-keys-components/public/index.ts +++ b/packages/kbn-search-api-keys-components/public/index.ts @@ -10,3 +10,4 @@ export * from './components/api_key_flyout_wrapper'; export * from './components/api_key_form'; export * from './hooks/use_search_api_key'; +export * from './providers/search_api_key_provider'; diff --git a/packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx b/packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx new file mode 100644 index 0000000000000..620f008a58c6c --- /dev/null +++ b/packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx @@ -0,0 +1,182 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React, { useCallback, useReducer, createContext, useEffect } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { APIKeyCreationResponse } from '@kbn/search-api-keys-api/server/types'; +import { APIRoutes } from '../types'; +import { Status } from '../constants'; + +const API_KEY_STORAGE_KEY = 'searchApiKey'; +const API_KEY_MASK = '•'.repeat(60); + +interface ApiKeyState { + status: Status; + apiKey: string | null; +} + +interface APIKeyContext { + displayedApiKey: string | null; + apiKey: string | null; + toggleApiKeyVisibility: () => void; + updateApiKey: ({ id, encoded }: { id: string; encoded: string }) => void; + status: Status; + apiKeyIsVisible: boolean; + initialiseKey: () => void; +} + +type Action = + | { type: 'SET_API_KEY'; apiKey: string; status: Status } + | { type: 'SET_STATUS'; status: Status } + | { type: 'CLEAR_API_KEY' } + | { type: 'TOGGLE_API_KEY_VISIBILITY' }; + +const initialState: ApiKeyState = { + apiKey: null, + status: Status.uninitialized, +}; + +const reducer = (state: ApiKeyState, action: Action): ApiKeyState => { + switch (action.type) { + case 'SET_API_KEY': + return { ...state, apiKey: action.apiKey, status: action.status }; + case 'SET_STATUS': + return { ...state, status: action.status }; + case 'TOGGLE_API_KEY_VISIBILITY': + return { + ...state, + status: + state.status === Status.showHiddenKey ? Status.showPreviewKey : Status.showHiddenKey, + }; + case 'CLEAR_API_KEY': + return { ...state, apiKey: null, status: Status.showCreateButton }; + default: + return state; + } +}; + +export const ApiKeyContext = createContext({ + displayedApiKey: null, + apiKey: null, + toggleApiKeyVisibility: () => {}, + updateApiKey: () => {}, + status: Status.uninitialized, + apiKeyIsVisible: false, + initialiseKey: () => {}, +}); + +export const SearchApiKeyProvider: React.FC = ({ children }) => { + const { http } = useKibana().services; + const [state, dispatch] = useReducer(reducer, initialState); + + const updateApiKey = useCallback(({ id, encoded }: { id: string; encoded: string }) => { + sessionStorage.setItem(API_KEY_STORAGE_KEY, JSON.stringify({ id, encoded })); + dispatch({ type: 'SET_API_KEY', apiKey: encoded, status: Status.showHiddenKey }); + }, []); + const handleShowKeyVisibility = useCallback(() => { + dispatch({ type: 'TOGGLE_API_KEY_VISIBILITY' }); + }, []); + const initialiseKey = useCallback(() => { + dispatch({ type: 'SET_STATUS', status: Status.loading }); + }, []); + const { mutateAsync: validateApiKey } = useMutation(async (id: string) => { + try { + if (!http?.post) { + throw new Error('HTTP service is unavailable'); + } + + const response = await http.post<{ isValid: boolean }>(APIRoutes.API_KEY_VALIDITY, { + body: JSON.stringify({ id }), + }); + + return response.isValid; + } catch (err) { + return false; + } + }); + const { mutateAsync: createApiKey } = useMutation({ + mutationFn: async () => { + try { + if (!http?.post) { + throw new Error('HTTP service is unavailable'); + } + + return await http.post(APIRoutes.API_KEYS); + } catch (err) { + if (err.response?.status === 400) { + dispatch({ type: 'SET_STATUS', status: Status.showCreateButton }); + } else if (err.response?.status === 403) { + dispatch({ type: 'SET_STATUS', status: Status.showUserPrivilegesError }); + } else { + throw err; + } + } + }, + onSuccess: (receivedApiKey) => { + if (receivedApiKey) { + sessionStorage.setItem( + API_KEY_STORAGE_KEY, + JSON.stringify({ id: receivedApiKey.id, encoded: receivedApiKey.encoded }) + ); + dispatch({ + type: 'SET_API_KEY', + apiKey: receivedApiKey.encoded, + status: Status.showHiddenKey, + }); + } + }, + }); + + useEffect(() => { + const initialiseApiKey = async () => { + try { + if (state.status === Status.loading) { + const storedKey = sessionStorage.getItem(API_KEY_STORAGE_KEY); + + if (storedKey) { + const { id, encoded } = JSON.parse(storedKey); + + if (await validateApiKey(id)) { + dispatch({ + type: 'SET_API_KEY', + apiKey: encoded, + status: Status.showHiddenKey, + }); + } else { + sessionStorage.removeItem(API_KEY_STORAGE_KEY); + dispatch({ + type: 'CLEAR_API_KEY', + }); + await createApiKey(); + } + } else { + await createApiKey(); + } + } + } catch (e) { + dispatch({ type: 'CLEAR_API_KEY' }); + } + }; + + initialiseApiKey(); + }, [state.status, createApiKey, validateApiKey]); + + const value: APIKeyContext = { + displayedApiKey: state.status === Status.showHiddenKey ? API_KEY_MASK : state.apiKey, + apiKey: state.apiKey, + toggleApiKeyVisibility: handleShowKeyVisibility, + updateApiKey, + status: state.status, + apiKeyIsVisible: state.status === Status.showPreviewKey, + initialiseKey, + }; + + return {children}; +}; diff --git a/x-pack/plugins/search_indices/public/application.tsx b/x-pack/plugins/search_indices/public/application.tsx index c196020319589..de0e26f455b2c 100644 --- a/x-pack/plugins/search_indices/public/application.tsx +++ b/x-pack/plugins/search_indices/public/application.tsx @@ -13,6 +13,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { I18nProvider } from '@kbn/i18n-react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { SearchApiKeyProvider } from '@kbn/search-api-keys-components/public'; import { UsageTrackerContextProvider } from './contexts/usage_tracker_context'; import { SearchIndicesServicesContextDeps } from './types'; @@ -29,7 +30,9 @@ export const renderApp = async ( - + + + diff --git a/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx b/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx index c629903b38444..d71046293021a 100644 --- a/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx +++ b/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx @@ -11,6 +11,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; +import { useSearchApiKey } from '@kbn/search-api-keys-components/public'; import { useKibana } from '../../hooks/use_kibana'; import { IngestCodeSnippetParameters } from '../../types'; import { LanguageSelector } from '../shared/language_selector'; @@ -68,6 +69,8 @@ export const AddDocumentsCodeExample = ({ }; }, [indexName, elasticsearchUrl, sampleDocument, codeSampleMappings, indexHasMappings]); + const { apiKey, apiKeyIsVisible } = useSearchApiKey(); + return ( { usageTracker.click([ AnalyticsEvents.indexDetailsInstallCodeCopy, @@ -131,6 +135,7 @@ export const AddDocumentsCodeExample = ({ })} language={Languages[selectedLanguage].codeBlockLanguage} code={selectedCodeExamples.updateMappingsCommand(codeParams)} + apiKey={apiKeyIsVisible ? apiKey : null} onCodeCopyClick={() => { usageTracker.click([ AnalyticsEvents.indexDetailsAddMappingsCodeCopy, @@ -146,6 +151,7 @@ export const AddDocumentsCodeExample = ({ title={ingestCodeExamples.ingestTitle} language={Languages[selectedLanguage].codeBlockLanguage} code={selectedCodeExamples.ingestCommand(codeParams)} + apiKey={apiKeyIsVisible ? apiKey : null} onCodeCopyClick={() => { usageTracker.click([ AnalyticsEvents.indexDetailsIngestDocumentsCodeCopy, diff --git a/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx b/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx index 4ddce94d685b0..539455eab4bf6 100644 --- a/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx @@ -16,6 +16,7 @@ import { EuiText, EuiThemeProvider, } from '@elastic/eui'; +import { API_KEY_PLACEHOLDER } from '../../constants'; export interface CodeSampleProps { id?: string; @@ -23,9 +24,17 @@ export interface CodeSampleProps { language: string; code: string; onCodeCopyClick?: React.MouseEventHandler; + apiKey?: string | null; } -export const CodeSample = ({ id, title, language, code, onCodeCopyClick }: CodeSampleProps) => { +export const CodeSample = ({ + id, + title, + language, + code, + apiKey, + onCodeCopyClick, +}: CodeSampleProps) => { const onCodeClick = React.useCallback( (e: React.MouseEvent) => { if (onCodeCopyClick === undefined) return; @@ -55,7 +64,7 @@ export const CodeSample = ({ id, title, language, code, onCodeCopyClick }: CodeS isCopyable transparentBackground > - {code} + {apiKey ? code.replace(API_KEY_PLACEHOLDER, apiKey) : code} diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx index 944e2fa6925d6..4aeaa4cb6c957 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx @@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer, EuiText } from '@elasti import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; -import { ApiKeyForm } from '@kbn/search-api-keys-components/public'; +import { ApiKeyForm, useSearchApiKey } from '@kbn/search-api-keys-components/public'; import { AnalyticsEvents } from '../../analytics/constants'; import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples'; @@ -57,6 +57,7 @@ export const CreateIndexCodeView = ({ const selectedCodeExample = useMemo(() => { return selectedCodeExamples[selectedLanguage]; }, [selectedLanguage, selectedCodeExamples]); + const { displayedApiKey, apiKeyIsVisible } = useSearchApiKey(); return ( @@ -122,10 +123,12 @@ export const CreateIndexCodeView = ({ /> )} { usageTracker.click([ diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_elasticsearch_start_page.ts b/x-pack/test_serverless/functional/page_objects/svl_search_elasticsearch_start_page.ts index 798d396258e75..4c6822c420fdb 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_search_elasticsearch_start_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_search_elasticsearch_start_page.ts @@ -90,5 +90,11 @@ export function SvlSearchElasticsearchStartPageProvider({ getService }: FtrProvi ); expect(await testSubjects.getAttribute('startO11yTrialBtn', 'target')).equal('_blank'); }, + async expectAPIKeyVisibleInCodeBlock(apiKey: string) { + await testSubjects.existOrFail('createIndex-code-block'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('createIndex-code-block')).to.contain(apiKey); + }); + }, }; } diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts b/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts index 7101571036c4e..dabc8dffac09e 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts @@ -157,5 +157,12 @@ export function SvlSearchIndexDetailPageProvider({ getService }: FtrProviderCont await testSubjects.existOrFail('tryInConsoleButton'); await testSubjects.click('tryInConsoleButton'); }, + + async expectAPIKeyToBeVisibleInCodeBlock(apiKey: string) { + await testSubjects.existOrFail('ingestDataCodeExample-code-block'); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + apiKey + ); + }, }; } diff --git a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts index aecfe217ba933..9e83057544003 100644 --- a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts +++ b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts @@ -109,6 +109,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlApiKeys.expectAPIKeyAvailable(); const newApiKeyUI = await pageObjects.svlApiKeys.getAPIKeyFromUI(); expect(newApiKeyUI).to.not.eql(apiKeyUI); + await pageObjects.svlSearchElasticsearchStartPage.expectAPIKeyVisibleInCodeBlock( + newApiKeyUI + ); }); it('should explicitly ask to create api key when project already has an apikey', async () => { @@ -133,18 +136,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const indexDetailsApiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); expect(apiKeyUI).to.eql(indexDetailsApiKey); - it('should have file upload link', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.clickFileUploadLink(); - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnMLFileUploadPage(); - }); + }); - it('should have o11y links', async () => { - await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); - await pageObjects.svlSearchElasticsearchStartPage.expectAnalyzeLogsLink(); - await pageObjects.svlSearchElasticsearchStartPage.expectO11yTrialLink(); - }); + it('should have file upload link', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.clickFileUploadLink(); + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnMLFileUploadPage(); }); + + it('should have o11y links', async () => { + await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); + await pageObjects.svlSearchElasticsearchStartPage.expectAnalyzeLogsLink(); + await pageObjects.svlSearchElasticsearchStartPage.expectO11yTrialLink(); + }); + describe('viewer', function () { before(async () => { await pageObjects.svlCommonPage.loginAsViewer(); diff --git a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts index 7192eca9d13c3..b6247f90b37c5 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts @@ -12,6 +12,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'svlCommonPage', 'embeddedConsole', 'svlSearchIndexDetailPage', + 'svlApiKeys', ]); const svlSearchNavigation = getService('svlSearchNavigation'); const es = getService('es'); @@ -22,6 +23,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('Search index detail page', () => { before(async () => { await pageObjects.svlCommonPage.loginWithRole('developer'); + await pageObjects.svlApiKeys.deleteAPIKeys(); }); after(async () => { await esDeleteAllIndices(indexName); @@ -82,6 +84,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); }); + it('should show api key', async () => { + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + await pageObjects.svlSearchIndexDetailPage.expectAPIKeyToBeVisibleInCodeBlock(apiKey); + }); + it('back to indices button should redirect to list page', async () => { await pageObjects.svlSearchIndexDetailPage.expectBackToIndicesButtonExists(); await pageObjects.svlSearchIndexDetailPage.clickBackToIndicesButton(); From f25dcec023499c64a303954e16932557724225ed Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Tue, 1 Oct 2024 16:02:13 +0100 Subject: [PATCH 34/36] updates based on feedback --- .github/CODEOWNERS | 2 +- package.json | 2 +- .../{public => }/index.ts | 8 ++++---- .../components/api_key_flyout_wrapper.tsx | 0 .../components/api_key_form.tsx | 0 .../{public => src}/constants.ts | 0 .../hooks/use_search_api_key.ts | 0 .../providers/search_api_key_provider.tsx | 2 +- .../{public => src}/types.ts | 0 .../tsconfig.json | 7 ++++--- .../README.md | 0 .../index.ts | 2 +- .../jest.config.js | 6 +++--- .../kibana.jsonc | 2 +- .../package.json | 2 +- .../src}/lib/create_key.ts | 2 +- .../src}/lib/get_key_by_id.ts | 2 +- .../src}/lib/privileges.ts | 0 .../src}/routes/routes.ts | 2 +- .../tsconfig.json | 6 ++++-- .../types.ts | 0 tsconfig.base.json | 10 ++++++---- .../search_indices/public/application.tsx | 2 +- .../add_documents_code_example.tsx | 19 ++++++++++++------- .../components/indices/details_page.tsx | 2 +- .../public/components/shared/code_sample.tsx | 13 ++----------- .../components/start/create_index_code.tsx | 9 +++++---- .../search_indices/server/routes/index.ts | 2 +- x-pack/plugins/search_indices/tsconfig.json | 4 ++-- yarn.lock | 4 ++-- 30 files changed, 56 insertions(+), 54 deletions(-) rename packages/kbn-search-api-keys-components/{public => }/index.ts (69%) rename packages/kbn-search-api-keys-components/{public => src}/components/api_key_flyout_wrapper.tsx (100%) rename packages/kbn-search-api-keys-components/{public => src}/components/api_key_form.tsx (100%) rename packages/kbn-search-api-keys-components/{public => src}/constants.ts (100%) rename packages/kbn-search-api-keys-components/{public => src}/hooks/use_search_api_key.ts (100%) rename packages/kbn-search-api-keys-components/{public => src}/providers/search_api_key_provider.tsx (99%) rename packages/kbn-search-api-keys-components/{public => src}/types.ts (100%) rename packages/{kbn-search-api-keys-api => kbn-search-api-keys-server}/README.md (100%) rename packages/{kbn-search-api-keys-api/server => kbn-search-api-keys-server}/index.ts (92%) rename packages/{kbn-search-api-keys-api => kbn-search-api-keys-server}/jest.config.js (85%) rename packages/{kbn-search-api-keys-api => kbn-search-api-keys-server}/kibana.jsonc (62%) rename packages/{kbn-search-api-keys-api => kbn-search-api-keys-server}/package.json (72%) rename packages/{kbn-search-api-keys-api/server => kbn-search-api-keys-server/src}/lib/create_key.ts (94%) rename packages/{kbn-search-api-keys-api/server => kbn-search-api-keys-server/src}/lib/get_key_by_id.ts (94%) rename packages/{kbn-search-api-keys-api/server => kbn-search-api-keys-server/src}/lib/privileges.ts (100%) rename packages/{kbn-search-api-keys-api/server => kbn-search-api-keys-server/src}/routes/routes.ts (98%) rename packages/{kbn-search-api-keys-api => kbn-search-api-keys-server}/tsconfig.json (85%) rename packages/{kbn-search-api-keys-api/server => kbn-search-api-keys-server}/types.ts (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 50928501e6e17..170a084a5ea1d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -752,7 +752,7 @@ src/plugins/screenshot_mode @elastic/appex-sharedux x-pack/examples/screenshotting_example @elastic/appex-sharedux x-pack/plugins/screenshotting @elastic/kibana-reporting-services packages/kbn-screenshotting-server @elastic/appex-sharedux -packages/kbn-search-api-keys-api @elastic/search-kibana +packages/kbn-search-api-keys-server @elastic/search-kibana packages/kbn-search-api-keys-components @elastic/search-kibana packages/kbn-search-api-panels @elastic/search-kibana x-pack/plugins/search_assistant @elastic/search-kibana diff --git a/package.json b/package.json index 3d2ccb9b9852d..a1fcd09d06845 100644 --- a/package.json +++ b/package.json @@ -769,8 +769,8 @@ "@kbn/screenshotting-example-plugin": "link:x-pack/examples/screenshotting_example", "@kbn/screenshotting-plugin": "link:x-pack/plugins/screenshotting", "@kbn/screenshotting-server": "link:packages/kbn-screenshotting-server", - "@kbn/search-api-keys-api": "link:packages/kbn-search-api-keys-api", "@kbn/search-api-keys-components": "link:packages/kbn-search-api-keys-components", + "@kbn/search-api-keys-server": "link:packages/kbn-search-api-keys-server", "@kbn/search-api-panels": "link:packages/kbn-search-api-panels", "@kbn/search-assistant": "link:x-pack/plugins/search_assistant", "@kbn/search-connectors": "link:packages/kbn-search-connectors", diff --git a/packages/kbn-search-api-keys-components/public/index.ts b/packages/kbn-search-api-keys-components/index.ts similarity index 69% rename from packages/kbn-search-api-keys-components/public/index.ts rename to packages/kbn-search-api-keys-components/index.ts index 3e3cb8e83a154..d188bdb956913 100644 --- a/packages/kbn-search-api-keys-components/public/index.ts +++ b/packages/kbn-search-api-keys-components/index.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export * from './components/api_key_flyout_wrapper'; -export * from './components/api_key_form'; -export * from './hooks/use_search_api_key'; -export * from './providers/search_api_key_provider'; +export * from './src/components/api_key_flyout_wrapper'; +export * from './src/components/api_key_form'; +export * from './src/hooks/use_search_api_key'; +export * from './src/providers/search_api_key_provider'; diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx b/packages/kbn-search-api-keys-components/src/components/api_key_flyout_wrapper.tsx similarity index 100% rename from packages/kbn-search-api-keys-components/public/components/api_key_flyout_wrapper.tsx rename to packages/kbn-search-api-keys-components/src/components/api_key_flyout_wrapper.tsx diff --git a/packages/kbn-search-api-keys-components/public/components/api_key_form.tsx b/packages/kbn-search-api-keys-components/src/components/api_key_form.tsx similarity index 100% rename from packages/kbn-search-api-keys-components/public/components/api_key_form.tsx rename to packages/kbn-search-api-keys-components/src/components/api_key_form.tsx diff --git a/packages/kbn-search-api-keys-components/public/constants.ts b/packages/kbn-search-api-keys-components/src/constants.ts similarity index 100% rename from packages/kbn-search-api-keys-components/public/constants.ts rename to packages/kbn-search-api-keys-components/src/constants.ts diff --git a/packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts b/packages/kbn-search-api-keys-components/src/hooks/use_search_api_key.ts similarity index 100% rename from packages/kbn-search-api-keys-components/public/hooks/use_search_api_key.ts rename to packages/kbn-search-api-keys-components/src/hooks/use_search_api_key.ts diff --git a/packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx b/packages/kbn-search-api-keys-components/src/providers/search_api_key_provider.tsx similarity index 99% rename from packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx rename to packages/kbn-search-api-keys-components/src/providers/search_api_key_provider.tsx index 620f008a58c6c..f3a81e72d3b2e 100644 --- a/packages/kbn-search-api-keys-components/public/providers/search_api_key_provider.tsx +++ b/packages/kbn-search-api-keys-components/src/providers/search_api_key_provider.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useReducer, createContext, useEffect } from 'react'; import { useMutation } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { APIKeyCreationResponse } from '@kbn/search-api-keys-api/server/types'; +import type { APIKeyCreationResponse } from '@kbn/search-api-keys-server/types'; import { APIRoutes } from '../types'; import { Status } from '../constants'; diff --git a/packages/kbn-search-api-keys-components/public/types.ts b/packages/kbn-search-api-keys-components/src/types.ts similarity index 100% rename from packages/kbn-search-api-keys-components/public/types.ts rename to packages/kbn-search-api-keys-components/src/types.ts diff --git a/packages/kbn-search-api-keys-components/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json index ec779956b1547..281bdf6203bbb 100644 --- a/packages/kbn-search-api-keys-components/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -4,7 +4,8 @@ "outDir": "target/types", }, "include": [ - "public/**/*", + "src/**/*", + "index.ts", ], "kbn_references": [ "@kbn/i18n", @@ -12,9 +13,9 @@ "@kbn/kibana-react-plugin", "@kbn/security-api-key-management", "@kbn/search-shared-ui", - "@kbn/search-api-keys-api" + "@kbn/search-api-keys-server" ], "exclude": [ "target/**/*", ] -} +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys-api/README.md b/packages/kbn-search-api-keys-server/README.md similarity index 100% rename from packages/kbn-search-api-keys-api/README.md rename to packages/kbn-search-api-keys-server/README.md diff --git a/packages/kbn-search-api-keys-api/server/index.ts b/packages/kbn-search-api-keys-server/index.ts similarity index 92% rename from packages/kbn-search-api-keys-api/server/index.ts rename to packages/kbn-search-api-keys-server/index.ts index 67646efc2e8fb..e9287e9debdd0 100644 --- a/packages/kbn-search-api-keys-api/server/index.ts +++ b/packages/kbn-search-api-keys-server/index.ts @@ -7,4 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export * from './routes/routes'; +export * from './src/routes/routes'; diff --git a/packages/kbn-search-api-keys-api/jest.config.js b/packages/kbn-search-api-keys-server/jest.config.js similarity index 85% rename from packages/kbn-search-api-keys-api/jest.config.js rename to packages/kbn-search-api-keys-server/jest.config.js index 997b5ed138a01..af09324461569 100644 --- a/packages/kbn-search-api-keys-api/jest.config.js +++ b/packages/kbn-search-api-keys-server/jest.config.js @@ -10,8 +10,8 @@ module.exports = { preset: '@kbn/test/jest_node', rootDir: '../..', - roots: ['/packages/kbn-search-api-keys-api'], - coverageDirectory: '/target/kibana-coverage/jest/packages/kbn-search-api-keys-api', + roots: ['/packages/kbn-search-api-keys-server'], + coverageDirectory: '/target/kibana-coverage/jest/packages/kbn-search-api-keys-server', coverageReporters: ['text', 'html'], - collectCoverageFrom: ['/packages/kbn-search-api-keys-api/**/*.{ts,tsx}'], + collectCoverageFrom: ['/packages/kbn-search-api-keys-server/**/*.{ts,tsx}'], }; diff --git a/packages/kbn-search-api-keys-api/kibana.jsonc b/packages/kbn-search-api-keys-server/kibana.jsonc similarity index 62% rename from packages/kbn-search-api-keys-api/kibana.jsonc rename to packages/kbn-search-api-keys-server/kibana.jsonc index 36501e7f34e51..52c6cd9653968 100644 --- a/packages/kbn-search-api-keys-api/kibana.jsonc +++ b/packages/kbn-search-api-keys-server/kibana.jsonc @@ -1,5 +1,5 @@ { "type": "shared-server", - "id": "@kbn/search-api-keys-api", + "id": "@kbn/search-api-keys-server", "owner": "@elastic/search-kibana" } \ No newline at end of file diff --git a/packages/kbn-search-api-keys-api/package.json b/packages/kbn-search-api-keys-server/package.json similarity index 72% rename from packages/kbn-search-api-keys-api/package.json rename to packages/kbn-search-api-keys-server/package.json index 536a7df06d1aa..6c891e7325a2e 100644 --- a/packages/kbn-search-api-keys-api/package.json +++ b/packages/kbn-search-api-keys-server/package.json @@ -1,5 +1,5 @@ { - "name": "@kbn/search-api-keys-api", + "name": "@kbn/search-api-keys-server", "private": true, "version": "1.0.0", "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" diff --git a/packages/kbn-search-api-keys-api/server/lib/create_key.ts b/packages/kbn-search-api-keys-server/src/lib/create_key.ts similarity index 94% rename from packages/kbn-search-api-keys-api/server/lib/create_key.ts rename to packages/kbn-search-api-keys-server/src/lib/create_key.ts index e74605c32440d..7bebe713810c8 100644 --- a/packages/kbn-search-api-keys-api/server/lib/create_key.ts +++ b/packages/kbn-search-api-keys-server/src/lib/create_key.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; -import type { APIKeyCreationResponse } from '../types'; +import type { APIKeyCreationResponse } from '../../types'; export async function createAPIKey( name: string, diff --git a/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts b/packages/kbn-search-api-keys-server/src/lib/get_key_by_id.ts similarity index 94% rename from packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts rename to packages/kbn-search-api-keys-server/src/lib/get_key_by_id.ts index a1337de4c4981..94ae64f56c0da 100644 --- a/packages/kbn-search-api-keys-api/server/lib/get_key_by_id.ts +++ b/packages/kbn-search-api-keys-server/src/lib/get_key_by_id.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; -import type { GetApiKeyResponse } from '../types'; +import type { GetApiKeyResponse } from '../../types'; export async function getAPIKeyById( id: string, diff --git a/packages/kbn-search-api-keys-api/server/lib/privileges.ts b/packages/kbn-search-api-keys-server/src/lib/privileges.ts similarity index 100% rename from packages/kbn-search-api-keys-api/server/lib/privileges.ts rename to packages/kbn-search-api-keys-server/src/lib/privileges.ts diff --git a/packages/kbn-search-api-keys-api/server/routes/routes.ts b/packages/kbn-search-api-keys-server/src/routes/routes.ts similarity index 98% rename from packages/kbn-search-api-keys-api/server/routes/routes.ts rename to packages/kbn-search-api-keys-server/src/routes/routes.ts index d3ddd4c4e21f1..77a08644f34a5 100644 --- a/packages/kbn-search-api-keys-api/server/routes/routes.ts +++ b/packages/kbn-search-api-keys-server/src/routes/routes.ts @@ -11,7 +11,7 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import { schema } from '@kbn/config-schema'; -import { APIRoutes } from '../types'; +import { APIRoutes } from '../../types'; import { getAPIKeyById } from '../lib/get_key_by_id'; import { createAPIKey } from '../lib/create_key'; import { fetchClusterHasApiKeys, fetchUserStartPrivileges } from '../lib/privileges'; diff --git a/packages/kbn-search-api-keys-api/tsconfig.json b/packages/kbn-search-api-keys-server/tsconfig.json similarity index 85% rename from packages/kbn-search-api-keys-api/tsconfig.json rename to packages/kbn-search-api-keys-server/tsconfig.json index b775a5eee6418..79fd6573c2443 100644 --- a/packages/kbn-search-api-keys-api/tsconfig.json +++ b/packages/kbn-search-api-keys-server/tsconfig.json @@ -4,7 +4,9 @@ "outDir": "target/types", }, "include": [ - "server/**/*" + "src/**/*", + "types.ts", + "index.ts" ], "kbn_references": [ "@kbn/core-elasticsearch-server", @@ -15,4 +17,4 @@ "exclude": [ "target/**/*", ] -} +} \ No newline at end of file diff --git a/packages/kbn-search-api-keys-api/server/types.ts b/packages/kbn-search-api-keys-server/types.ts similarity index 100% rename from packages/kbn-search-api-keys-api/server/types.ts rename to packages/kbn-search-api-keys-server/types.ts diff --git a/tsconfig.base.json b/tsconfig.base.json index 5cbee514d63b7..aefbd2d12ffd5 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1498,10 +1498,10 @@ "@kbn/screenshotting-plugin/*": ["x-pack/plugins/screenshotting/*"], "@kbn/screenshotting-server": ["packages/kbn-screenshotting-server"], "@kbn/screenshotting-server/*": ["packages/kbn-screenshotting-server/*"], - "@kbn/search-api-keys-api": ["packages/kbn-search-api-keys-api"], - "@kbn/search-api-keys-api/*": ["packages/kbn-search-api-keys-api/*"], "@kbn/search-api-keys-components": ["packages/kbn-search-api-keys-components"], "@kbn/search-api-keys-components/*": ["packages/kbn-search-api-keys-components/*"], + "@kbn/search-api-keys-server": ["packages/kbn-search-api-keys-server"], + "@kbn/search-api-keys-server/*": ["packages/kbn-search-api-keys-server/*"], "@kbn/search-api-panels": ["packages/kbn-search-api-panels"], "@kbn/search-api-panels/*": ["packages/kbn-search-api-panels/*"], "@kbn/search-assistant": ["x-pack/plugins/search_assistant"], @@ -2000,7 +2000,9 @@ "@kbn/zod-helpers/*": ["packages/kbn-zod-helpers/*"], // END AUTOMATED PACKAGE LISTING // Allows for importing from `kibana` package for the exported types. - "@emotion/core": ["typings/@emotion"] + "@emotion/core": [ + "typings/@emotion" + ] }, // Support .tsx files and transform JSX into calls to React.createElement "jsx": "react", @@ -2074,4 +2076,4 @@ "@kbn/ambient-storybook-types" ] } -} +} \ No newline at end of file diff --git a/x-pack/plugins/search_indices/public/application.tsx b/x-pack/plugins/search_indices/public/application.tsx index de0e26f455b2c..e3f537998d5ea 100644 --- a/x-pack/plugins/search_indices/public/application.tsx +++ b/x-pack/plugins/search_indices/public/application.tsx @@ -13,7 +13,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { I18nProvider } from '@kbn/i18n-react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { SearchApiKeyProvider } from '@kbn/search-api-keys-components/public'; +import { SearchApiKeyProvider } from '@kbn/search-api-keys-components'; import { UsageTrackerContextProvider } from './contexts/usage_tracker_context'; import { SearchIndicesServicesContextDeps } from './types'; diff --git a/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx b/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx index d71046293021a..aa8fd525c8a44 100644 --- a/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx +++ b/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx @@ -11,7 +11,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; -import { useSearchApiKey } from '@kbn/search-api-keys-components/public'; +import { useSearchApiKey } from '@kbn/search-api-keys-components'; import { useKibana } from '../../hooks/use_kibana'; import { IngestCodeSnippetParameters } from '../../types'; import { LanguageSelector } from '../shared/language_selector'; @@ -59,6 +59,7 @@ export const AddDocumentsCodeExample = ({ // TODO: implement smart document generation return generateSampleDocument(codeSampleMappings); }, [codeSampleMappings]); + const { apiKey, apiKeyIsVisible } = useSearchApiKey(); const codeParams: IngestCodeSnippetParameters = useMemo(() => { return { indexName, @@ -66,10 +67,17 @@ export const AddDocumentsCodeExample = ({ sampleDocument, indexHasMappings, mappingProperties: codeSampleMappings, + apiKey: apiKeyIsVisible && apiKey ? apiKey : undefined, }; - }, [indexName, elasticsearchUrl, sampleDocument, codeSampleMappings, indexHasMappings]); - - const { apiKey, apiKeyIsVisible } = useSearchApiKey(); + }, [ + indexName, + elasticsearchUrl, + sampleDocument, + codeSampleMappings, + indexHasMappings, + apiKeyIsVisible, + apiKey, + ]); return ( { usageTracker.click([ AnalyticsEvents.indexDetailsInstallCodeCopy, @@ -135,7 +142,6 @@ export const AddDocumentsCodeExample = ({ })} language={Languages[selectedLanguage].codeBlockLanguage} code={selectedCodeExamples.updateMappingsCommand(codeParams)} - apiKey={apiKeyIsVisible ? apiKey : null} onCodeCopyClick={() => { usageTracker.click([ AnalyticsEvents.indexDetailsAddMappingsCodeCopy, @@ -151,7 +157,6 @@ export const AddDocumentsCodeExample = ({ title={ingestCodeExamples.ingestTitle} language={Languages[selectedLanguage].codeBlockLanguage} code={selectedCodeExamples.ingestCommand(codeParams)} - apiKey={apiKeyIsVisible ? apiKey : null} onCodeCopyClick={() => { usageTracker.click([ AnalyticsEvents.indexDetailsIngestDocumentsCodeCopy, diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx index 91626d91f8577..94abecd137005 100644 --- a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx @@ -26,7 +26,7 @@ import { useParams } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; -import { ApiKeyForm } from '@kbn/search-api-keys-components/public'; +import { ApiKeyForm } from '@kbn/search-api-keys-components'; import { useIndex } from '../../hooks/api/use_index'; import { useKibana } from '../../hooks/use_kibana'; import { ConnectionDetails } from '../connection_details/connection_details'; diff --git a/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx b/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx index 539455eab4bf6..4ddce94d685b0 100644 --- a/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/code_sample.tsx @@ -16,7 +16,6 @@ import { EuiText, EuiThemeProvider, } from '@elastic/eui'; -import { API_KEY_PLACEHOLDER } from '../../constants'; export interface CodeSampleProps { id?: string; @@ -24,17 +23,9 @@ export interface CodeSampleProps { language: string; code: string; onCodeCopyClick?: React.MouseEventHandler; - apiKey?: string | null; } -export const CodeSample = ({ - id, - title, - language, - code, - apiKey, - onCodeCopyClick, -}: CodeSampleProps) => { +export const CodeSample = ({ id, title, language, code, onCodeCopyClick }: CodeSampleProps) => { const onCodeClick = React.useCallback( (e: React.MouseEvent) => { if (onCodeCopyClick === undefined) return; @@ -64,7 +55,7 @@ export const CodeSample = ({ isCopyable transparentBackground > - {apiKey ? code.replace(API_KEY_PLACEHOLDER, apiKey) : code} + {code} diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx index 4aeaa4cb6c957..401173fecc0da 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx @@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer, EuiText } from '@elasti import { i18n } from '@kbn/i18n'; import { TryInConsoleButton } from '@kbn/try-in-console'; -import { ApiKeyForm, useSearchApiKey } from '@kbn/search-api-keys-components/public'; +import { ApiKeyForm, useSearchApiKey } from '@kbn/search-api-keys-components'; import { AnalyticsEvents } from '../../analytics/constants'; import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples'; @@ -48,16 +48,18 @@ export const CreateIndexCodeView = ({ [usageTracker, changeCodingLanguage] ); const elasticsearchUrl = useElasticsearchUrl(); + const { apiKey, apiKeyIsVisible } = useSearchApiKey(); + const codeParams = useMemo(() => { return { indexName: createIndexForm.indexName || undefined, elasticsearchURL: elasticsearchUrl, + apiKey: apiKeyIsVisible && apiKey ? apiKey : undefined, }; - }, [createIndexForm.indexName, elasticsearchUrl]); + }, [createIndexForm.indexName, elasticsearchUrl, apiKeyIsVisible, apiKey]); const selectedCodeExample = useMemo(() => { return selectedCodeExamples[selectedLanguage]; }, [selectedLanguage, selectedCodeExamples]); - const { displayedApiKey, apiKeyIsVisible } = useSearchApiKey(); return ( @@ -128,7 +130,6 @@ export const CreateIndexCodeView = ({ defaultMessage: 'Connect and create an index', })} language={Languages[selectedLanguage].codeBlockLanguage} - apiKey={apiKeyIsVisible ? displayedApiKey : null} code={selectedCodeExample.createIndex(codeParams)} onCodeCopyClick={() => { usageTracker.click([ diff --git a/x-pack/plugins/search_indices/server/routes/index.ts b/x-pack/plugins/search_indices/server/routes/index.ts index a383c8276c5a5..451647eb22774 100644 --- a/x-pack/plugins/search_indices/server/routes/index.ts +++ b/x-pack/plugins/search_indices/server/routes/index.ts @@ -8,7 +8,7 @@ import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; -import { registerSearchApiKeysRoutes } from '@kbn/search-api-keys-api/server'; +import { registerSearchApiKeysRoutes } from '@kbn/search-api-keys-server'; import { registerIndicesRoutes } from './indices'; import { registerStatusRoutes } from './status'; diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index ca6763a6a8563..6d560ef1e96e4 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -34,11 +34,11 @@ "@kbn/cloud-plugin", "@kbn/search-index-documents", "@kbn/es-types", - "@kbn/search-api-keys-api", + "@kbn/search-api-keys-server", "@kbn/search-api-keys-components", "@kbn/search-shared-ui" ], "exclude": [ "target/**/*", ] -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index feeb131a69018..fdad4289c3b30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6267,11 +6267,11 @@ version "0.0.0" uid "" -"@kbn/search-api-keys-api@link:packages/kbn-search-api-keys-api": +"@kbn/search-api-keys-components@link:packages/kbn-search-api-keys-components": version "0.0.0" uid "" -"@kbn/search-api-keys-components@link:packages/kbn-search-api-keys-components": +"@kbn/search-api-keys-server@link:packages/kbn-search-api-keys-server": version "0.0.0" uid "" From cd87f441ef7c4dccb448fa6b48fc102e7b67e465 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:17:22 +0000 Subject: [PATCH 35/36] [CI] Auto-commit changed files from 'node scripts/generate codeowners' --- .github/CODEOWNERS | 2 +- packages/kbn-search-api-keys-components/tsconfig.json | 2 +- packages/kbn-search-api-keys-server/tsconfig.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 170a084a5ea1d..4730de32b996d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -752,8 +752,8 @@ src/plugins/screenshot_mode @elastic/appex-sharedux x-pack/examples/screenshotting_example @elastic/appex-sharedux x-pack/plugins/screenshotting @elastic/kibana-reporting-services packages/kbn-screenshotting-server @elastic/appex-sharedux -packages/kbn-search-api-keys-server @elastic/search-kibana packages/kbn-search-api-keys-components @elastic/search-kibana +packages/kbn-search-api-keys-server @elastic/search-kibana packages/kbn-search-api-panels @elastic/search-kibana x-pack/plugins/search_assistant @elastic/search-kibana packages/kbn-search-connectors @elastic/search-kibana diff --git a/packages/kbn-search-api-keys-components/tsconfig.json b/packages/kbn-search-api-keys-components/tsconfig.json index 281bdf6203bbb..e81fb5bc36996 100644 --- a/packages/kbn-search-api-keys-components/tsconfig.json +++ b/packages/kbn-search-api-keys-components/tsconfig.json @@ -18,4 +18,4 @@ "exclude": [ "target/**/*", ] -} \ No newline at end of file +} diff --git a/packages/kbn-search-api-keys-server/tsconfig.json b/packages/kbn-search-api-keys-server/tsconfig.json index 79fd6573c2443..9a82ed8904725 100644 --- a/packages/kbn-search-api-keys-server/tsconfig.json +++ b/packages/kbn-search-api-keys-server/tsconfig.json @@ -17,4 +17,4 @@ "exclude": [ "target/**/*", ] -} \ No newline at end of file +} From b7029a8623c6b0f1d35075c7d7e5ffd8d1c05ed5 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:31:08 +0000 Subject: [PATCH 36/36] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/plugins/search_indices/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index 6d560ef1e96e4..a564b87c7f6e6 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -41,4 +41,4 @@ "exclude": [ "target/**/*", ] -} \ No newline at end of file +}