[8.12] [Search] Fix API key flyout bugfixes (#173547) (#173567)

# Backport

This will backport the following commits from `main` to `8.12`:
- [[Search] Fix API key flyout bugfixes
(#173547)](https://github.com/elastic/kibana/pull/173547)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Sander
Philipse","email":"94373878+sphilipse@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-12-18T19:25:48Z","message":"[Search]
Fix API key flyout bugfixes (#173547)\n\n## Summary\r\n\r\nThis fixes a
couple of API key flyout bugfixes:\r\n\r\n- created API key now shows up
regardless of where you opened the flyout\r\nfrom\r\n- Header action has
a max width of 256px and wraps the cloud ID and\r\nelasticsearch
endpoint\r\n- API key is scrolled into view when
created","sha":"7016c042336d154e8e570d268a3031cc170bc0af","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:EnterpriseSearch","v8.12.0","v8.13.0"],"number":173547,"url":"https://github.com/elastic/kibana/pull/173547","mergeCommit":{"message":"[Search]
Fix API key flyout bugfixes (#173547)\n\n## Summary\r\n\r\nThis fixes a
couple of API key flyout bugfixes:\r\n\r\n- created API key now shows up
regardless of where you opened the flyout\r\nfrom\r\n- Header action has
a max width of 256px and wraps the cloud ID and\r\nelasticsearch
endpoint\r\n- API key is scrolled into view when
created","sha":"7016c042336d154e8e570d268a3031cc170bc0af"}},"sourceBranch":"main","suggestedTargetBranches":["8.12"],"targetPullRequestStates":[{"branch":"8.12","label":"v8.12.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.13.0","labelRegex":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/173547","number":173547,"mergeCommit":{"message":"[Search]
Fix API key flyout bugfixes (#173547)\n\n## Summary\r\n\r\nThis fixes a
couple of API key flyout bugfixes:\r\n\r\n- created API key now shows up
regardless of where you opened the flyout\r\nfrom\r\n- Header action has
a max width of 256px and wraps the cloud ID and\r\nelasticsearch
endpoint\r\n- API key is scrolled into view when
created","sha":"7016c042336d154e8e570d268a3031cc170bc0af"}}]}]
BACKPORT-->

Co-authored-by: Sander Philipse <94373878+sphilipse@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2023-12-18 15:42:40 -05:00 committed by GitHub
parent 134d51bbdf
commit 34f6840f54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 129 additions and 101 deletions

View file

@ -15,18 +15,13 @@ import { i18n } from '@kbn/i18n';
import { LanguageDefinitionSnippetArguments } from '@kbn/search-api-panels'; import { LanguageDefinitionSnippetArguments } from '@kbn/search-api-panels';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants'; import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants';
import { Status } from '../../../../../common/types/api';
import { CreateApiKeyAPILogic } from '../../../enterprise_search_overview/api/create_elasticsearch_api_key_logic';
import { FetchApiKeysAPILogic } from '../../../enterprise_search_overview/api/fetch_api_keys_logic'; import { FetchApiKeysAPILogic } from '../../../enterprise_search_overview/api/fetch_api_keys_logic';
import { CreateApiKeyFlyout } from '../../../shared/api_key/create_api_key_flyout'; import { CreateApiKeyFlyout } from '../../../shared/api_key/create_api_key_flyout';
import { useCloudDetails } from '../../../shared/cloud_details/cloud_details'; import { useCloudDetails } from '../../../shared/cloud_details/cloud_details';
import { GettingStarted } from '../../../shared/getting_started/getting_started'; import { GettingStarted } from '../../../shared/getting_started/getting_started';
import { KibanaLogic } from '../../../shared/kibana/kibana_logic';
import { EnterpriseSearchElasticsearchPageTemplate } from '../layout'; import { EnterpriseSearchElasticsearchPageTemplate } from '../layout';
export const ElasticsearchGuide = () => { export const ElasticsearchGuide = () => {
const { user } = useValues(KibanaLogic);
const cloudContext = useCloudDetails(); const cloudContext = useCloudDetails();
const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
@ -36,8 +31,6 @@ export const ElasticsearchGuide = () => {
url: cloudContext.elasticsearchUrl || ELASTICSEARCH_URL_PLACEHOLDER, url: cloudContext.elasticsearchUrl || ELASTICSEARCH_URL_PLACEHOLDER,
}; };
const { makeRequest } = useActions(FetchApiKeysAPILogic); const { makeRequest } = useActions(FetchApiKeysAPILogic);
const { makeRequest: saveApiKey } = useActions(CreateApiKeyAPILogic);
const { error, status } = useValues(CreateApiKeyAPILogic);
const { data } = useValues(FetchApiKeysAPILogic); const { data } = useValues(FetchApiKeysAPILogic);
const apiKeys = data?.api_keys || []; const apiKeys = data?.api_keys || [];
@ -45,15 +38,7 @@ export const ElasticsearchGuide = () => {
return ( return (
<EnterpriseSearchElasticsearchPageTemplate> <EnterpriseSearchElasticsearchPageTemplate>
{isFlyoutOpen && ( {isFlyoutOpen && <CreateApiKeyFlyout onClose={() => setIsFlyoutOpen(false)} />}
<CreateApiKeyFlyout
error={error?.body?.message}
isLoading={status === Status.LOADING}
onClose={() => setIsFlyoutOpen(false)}
setApiKey={saveApiKey}
username={user?.full_name || user?.username || ''}
/>
)}
<EuiTitle size="l" data-test-subj="elasticsearchGuide"> <EuiTitle size="l" data-test-subj="elasticsearchGuide">
<h1> <h1>
{i18n.translate('xpack.enterpriseSearch.content.overview.gettingStarted.pageTitle', { {i18n.translate('xpack.enterpriseSearch.content.overview.gettingStarted.pageTitle', {

View file

@ -30,7 +30,7 @@ import {
INGESTION_METHOD_IDS, INGESTION_METHOD_IDS,
} from '../../../../../common/constants'; } from '../../../../../common/constants';
import apiLogo from '../../../../assets/images/api_cloud.svg'; import apiLogo from '../../../../assets/images/api_image.png';
import fileUploadLogo from '../../../../assets/images/file_upload_logo.svg'; import fileUploadLogo from '../../../../assets/images/file_upload_logo.svg';
import sampleDataLogo from '../../../../assets/images/sample_data_logo.svg'; import sampleDataLogo from '../../../../assets/images/sample_data_logo.svg';
import connectorLogo from '../../../../assets/images/search_connector.svg'; import connectorLogo from '../../../../assets/images/search_connector.svg';

View file

@ -59,7 +59,7 @@ export const ProductSelector: React.FC = () => {
</EuiPageTemplate.Section> </EuiPageTemplate.Section>
<EuiPageTemplate.Section color="subdued"> <EuiPageTemplate.Section color="subdued">
<ApiKeyPanel user={user} /> <ApiKeyPanel />
<EuiSpacer size="xl" /> <EuiSpacer size="xl" />
<EuiTitle> <EuiTitle>
<h4> <h4>

View file

@ -26,29 +26,19 @@ import {
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react'; import { FormattedMessage } from '@kbn/i18n-react';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants'; import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants';
import { AuthenticatedUser } from '@kbn/security-plugin/common';
import { Status } from '../../../../common/types/api';
import { CreateApiKeyAPILogic } from '../../enterprise_search_overview/api/create_elasticsearch_api_key_logic';
import { FetchApiKeysAPILogic } from '../../enterprise_search_overview/api/fetch_api_keys_logic'; import { FetchApiKeysAPILogic } from '../../enterprise_search_overview/api/fetch_api_keys_logic';
import { KibanaLogic } from '../kibana'; import { KibanaLogic } from '../kibana';
import { CreateApiKeyFlyout } from './create_api_key_flyout'; import { CreateApiKeyFlyout } from './create_api_key_flyout';
interface ApiKeyPanelProps {
user: AuthenticatedUser | null;
}
const COPIED_LABEL = i18n.translate('xpack.enterpriseSearch.overview.apiKey.copied', { const COPIED_LABEL = i18n.translate('xpack.enterpriseSearch.overview.apiKey.copied', {
defaultMessage: 'Copied', defaultMessage: 'Copied',
}); });
export const ApiKeyPanel: React.FC<ApiKeyPanelProps> = ({ user }) => { export const ApiKeyPanel: React.FC = () => {
const { cloud, navigateToUrl } = useValues(KibanaLogic); const { cloud, navigateToUrl } = useValues(KibanaLogic);
const { makeRequest } = useActions(FetchApiKeysAPILogic); const { makeRequest } = useActions(FetchApiKeysAPILogic);
const { makeRequest: saveApiKey } = useActions(CreateApiKeyAPILogic);
const { error, status } = useValues(CreateApiKeyAPILogic);
const { data } = useValues(FetchApiKeysAPILogic); const { data } = useValues(FetchApiKeysAPILogic);
const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
@ -60,15 +50,7 @@ export const ApiKeyPanel: React.FC<ApiKeyPanelProps> = ({ user }) => {
return ( return (
<> <>
{isFlyoutOpen && ( {isFlyoutOpen && <CreateApiKeyFlyout onClose={() => setIsFlyoutOpen(false)} />}
<CreateApiKeyFlyout
error={error?.body?.message}
isLoading={status === Status.LOADING}
onClose={() => setIsFlyoutOpen(false)}
setApiKey={saveApiKey}
username={user?.full_name || user?.username || ''}
/>
)}
<EuiSplitPanel.Outer> <EuiSplitPanel.Outer>
{Boolean(cloud) && ( {Boolean(cloud) && (
<EuiSplitPanel.Inner> <EuiSplitPanel.Inner>

View file

@ -4,10 +4,12 @@
* 2.0; you may not use this file except in compliance with the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License
* 2.0. * 2.0.
*/ */
import React, { useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { css } from '@emotion/react'; import { css } from '@emotion/react';
import { useValues, useActions } from 'kea';
import { import {
useEuiTheme, useEuiTheme,
EuiAccordion, EuiAccordion,
@ -31,12 +33,14 @@ import {
EuiText, EuiText,
EuiTitle, EuiTitle,
} from '@elastic/eui'; } from '@elastic/eui';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { import { Status } from '../../../../common/types/api';
CreateAPIKeyArgs,
CreateApiKeyResponse, import { CreateApiKeyAPILogic } from '../../enterprise_search_overview/api/create_elasticsearch_api_key_logic';
} from '../../enterprise_search_overview/api/create_elasticsearch_api_key_logic';
import { KibanaLogic } from '../kibana';
import { BasicSetupForm, DEFAULT_EXPIRES_VALUE } from './basic_setup_form'; import { BasicSetupForm, DEFAULT_EXPIRES_VALUE } from './basic_setup_form';
import { MetadataForm } from './metadata_form'; import { MetadataForm } from './metadata_form';
@ -57,12 +61,7 @@ const DEFAULT_METADATA = `{
}`; }`;
interface CreateApiKeyFlyoutProps { interface CreateApiKeyFlyoutProps {
createdApiKey?: CreateApiKeyResponse;
error?: string;
isLoading: boolean;
onClose: () => void; onClose: () => void;
setApiKey: (apiKey: CreateAPIKeyArgs) => void;
username: string;
} }
export const CANCEL_LABEL: string = i18n.translate('xpack.enterpriseSearch.cancel', { export const CANCEL_LABEL: string = i18n.translate('xpack.enterpriseSearch.cancel', {
@ -93,14 +92,7 @@ const INVALID_JSON_ERROR: string = i18n.translate('xpack.enterpriseSearch.invali
defaultMessage: 'Invalid JSON', defaultMessage: 'Invalid JSON',
}); });
export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({ onClose }) => {
createdApiKey,
error,
isLoading,
onClose,
username,
setApiKey,
}) => {
const { euiTheme } = useEuiTheme(); const { euiTheme } = useEuiTheme();
const [name, setName] = useState(''); const [name, setName] = useState('');
const [expires, setExpires] = useState<string | null>(DEFAULT_EXPIRES_VALUE); const [expires, setExpires] = useState<string | null>(DEFAULT_EXPIRES_VALUE);
@ -113,6 +105,14 @@ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({
const [metadataEnabled, setMetadataEnabled] = useState<boolean>(false); const [metadataEnabled, setMetadataEnabled] = useState<boolean>(false);
const [metadataOpen, setMetadataOpen] = useState<'open' | 'closed'>('closed'); const [metadataOpen, setMetadataOpen] = useState<'open' | 'closed'>('closed');
const { user } = useValues(KibanaLogic);
const { makeRequest: saveApiKey, apiReset } = useActions(CreateApiKeyAPILogic);
const { data: createdApiKey, error, status } = useValues(CreateApiKeyAPILogic);
const isLoading = status === Status.LOADING;
const username = user?.full_name || user?.username || user?.email || '';
const togglePrivileges = (e: EuiSwitchEvent) => { const togglePrivileges = (e: EuiSwitchEvent) => {
const enabled = e.target.checked; const enabled = e.target.checked;
setPrivilegesEnabled(enabled); setPrivilegesEnabled(enabled);
@ -151,7 +151,7 @@ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({
if (metadataError) setMetadataError(undefined); if (metadataError) setMetadataError(undefined);
const expiration = expires !== null ? `${expires}d` : undefined; const expiration = expires !== null ? `${expires}d` : undefined;
setApiKey({ saveApiKey({
expiration, expiration,
metadata: parsedMetadata, metadata: parsedMetadata,
name, name,
@ -159,9 +159,22 @@ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({
}); });
}; };
const apiKeyRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (createdApiKey && apiKeyRef) {
apiKeyRef.current?.scrollIntoView();
}
}, [createdApiKey, apiKeyRef]);
const closeFlyOut = () => {
apiReset();
onClose();
};
return ( return (
<EuiFlyout <EuiFlyout
onClose={onClose} onClose={closeFlyOut}
css={css` css={css`
max-width: calc(${euiTheme.size.xxxxl} * 10); max-width: calc(${euiTheme.size.xxxxl} * 10);
`} `}
@ -176,14 +189,11 @@ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({
</EuiTitle> </EuiTitle>
</EuiFlyoutHeader> </EuiFlyoutHeader>
<EuiFlyoutBody> <EuiFlyoutBody>
<div ref={apiKeyRef} />
{createdApiKey && ( {createdApiKey && (
<> <>
<EuiPanel <EuiSpacer />
css={css` <EuiPanel color="success" data-test-subj="api-key-create-success-panel">
background-color: transparentize($euiColorSuccess, 0.9);
`}
data-test-subj="api-key-create-success-panel"
>
<EuiStep <EuiStep
css={css` css={css`
.euiStep__content { .euiStep__content {
@ -221,7 +231,7 @@ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({
})} })}
data-test-subj="create-api-key-error-callout" data-test-subj="create-api-key-error-callout"
> >
{error} {error.body?.message}
</EuiCallOut> </EuiCallOut>
)} )}
<EuiPanel hasBorder> <EuiPanel hasBorder>
@ -384,7 +394,7 @@ export const CreateApiKeyFlyout: React.FC<CreateApiKeyFlyoutProps> = ({
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<EuiButtonEmpty <EuiButtonEmpty
isDisabled={isLoading} isDisabled={isLoading}
onClick={onClose} onClick={closeFlyOut}
data-test-subj="create-api-key-cancel" data-test-subj="create-api-key-cancel"
> >
{CANCEL_LABEL} {CANCEL_LABEL}

View file

@ -7,10 +7,14 @@
import { LanguageDefinition } from '@kbn/search-api-panels'; import { LanguageDefinition } from '@kbn/search-api-panels';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToJSON } from './helpers'; import { ingestKeysToJSON } from './helpers';
export const consoleDefinition: Partial<LanguageDefinition> = { export const consoleDefinition: Partial<LanguageDefinition> = {
buildSearchQuery: ({ indexName }) => `POST /${indexName ?? 'books'}/_search?pretty buildSearchQuery: ({ indexName = INDEX_NAME_PLACEHOLDER }) => `POST /${
indexName ?? 'books'
}/_search?pretty
{ {
"query": { "query": {
"query_string": { "query_string": {
@ -18,7 +22,11 @@ export const consoleDefinition: Partial<LanguageDefinition> = {
} }
} }
}`, }`,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : '';
return `POST _bulk?pretty${ingestPipeline ? `&pipeline=${ingestPipeline}` : ''} return `POST _bulk?pretty${ingestPipeline ? `&pipeline=${ingestPipeline}` : ''}
{ "index" : { "_index" : "${indexName}" } } { "index" : { "_index" : "${indexName}" } }

View file

@ -10,10 +10,14 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels';
import { docLinks } from '../../doc_links'; import { docLinks } from '../../doc_links';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToJSON } from './helpers'; import { ingestKeysToJSON } from './helpers';
export const curlDefinition: LanguageDefinition = { export const curlDefinition: LanguageDefinition = {
buildSearchQuery: ({ indexName }) => `curl -X POST "\$\{ES_URL\}/${indexName}/_search?pretty" \\ buildSearchQuery: ({
indexName = INDEX_NAME_PLACEHOLDER,
}) => `curl -X POST "\$\{ES_URL\}/${indexName}/_search?pretty" \\
-H "Authorization: ApiKey "\$\{API_KEY\}"" \\ -H "Authorization: ApiKey "\$\{API_KEY\}"" \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-d' -d'
@ -35,7 +39,11 @@ export API_KEY="${apiKey}"`,
}, },
iconType: 'curl.svg', iconType: 'curl.svg',
id: Languages.CURL, id: Languages.CURL,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : '';
return `curl -X POST "\$\{ES_URL\}/_bulk?pretty${ return `curl -X POST "\$\{ES_URL\}/_bulk?pretty${
ingestPipeline ? `&pipeline=${ingestPipeline}` : '' ingestPipeline ? `&pipeline=${ingestPipeline}` : ''
@ -67,7 +75,7 @@ brew install curl`,
defaultMessage: 'cURL', defaultMessage: 'cURL',
}), }),
languageStyling: 'shell', languageStyling: 'shell',
testConnection: ({ indexName }) => `curl "\$\{ES_URL\}/${indexName}" \\ testConnection: ({ indexName = INDEX_NAME_PLACEHOLDER }) => `curl "\$\{ES_URL\}/${indexName}" \\
-H "Authorization: ApiKey "\$\{API_KEY\}"" \\ -H "Authorization: ApiKey "\$\{API_KEY\}"" \\
-H "Content-Type: application/json"`, -H "Content-Type: application/json"`,
}; };

View file

@ -10,10 +10,12 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels';
import { docLinks } from '../../doc_links'; import { docLinks } from '../../doc_links';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToJSON } from './helpers'; import { ingestKeysToJSON } from './helpers';
export const goDefinition: LanguageDefinition = { export const goDefinition: LanguageDefinition = {
buildSearchQuery: ({ indexName }) => `searchResp, err := es.Search( buildSearchQuery: ({ indexName = INDEX_NAME_PLACEHOLDER }) => `searchResp, err := es.Search(
es.Search.WithContext(context.Background()), es.Search.WithContext(context.Background()),
es.Search.WithIndex("${indexName}"), es.Search.WithIndex("${indexName}"),
es.Search.WithQuery("snow"), es.Search.WithQuery("snow"),
@ -58,7 +60,11 @@ if err != nil {
}, },
iconType: 'go.svg', iconType: 'go.svg',
id: Languages.GO, id: Languages.GO,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : '';
return `buf := bytes.NewBufferString(\` return `buf := bytes.NewBufferString(\`
{"index":{"_id":"9780553351927"}} {"index":{"_id":"9780553351927"}}

View file

@ -10,10 +10,12 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels';
import { docLinks } from '../../doc_links'; import { docLinks } from '../../doc_links';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToJSON } from './helpers'; import { ingestKeysToJSON } from './helpers';
export const javascriptDefinition: LanguageDefinition = { export const javascriptDefinition: LanguageDefinition = {
buildSearchQuery: ({ indexName }) => `// Let's search! buildSearchQuery: ({ indexName = INDEX_NAME_PLACEHOLDER }) => `// Let's search!
const searchResult = await client.search({ const searchResult = await client.search({
index: '${indexName}', index: '${indexName}',
q: 'snow' q: 'snow'
@ -37,7 +39,11 @@ const client = new Client({
}, },
iconType: 'javascript.svg', iconType: 'javascript.svg',
id: Languages.JAVASCRIPT, id: Languages.JAVASCRIPT,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : '';
return `// Sample data books return `// Sample data books
const dataset = [ const dataset = [

View file

@ -10,10 +10,12 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels';
import { docLinks } from '../../doc_links'; import { docLinks } from '../../doc_links';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToPHP } from './helpers'; import { ingestKeysToPHP } from './helpers';
export const phpDefinition: LanguageDefinition = { export const phpDefinition: LanguageDefinition = {
buildSearchQuery: ({ indexName }) => `$params = [ buildSearchQuery: ({ indexName = INDEX_NAME_PLACEHOLDER }) => `$params = [
'index' => '${indexName}', 'index' => '${indexName}',
'body' => [ 'body' => [
'q' => 'snow' 'q' => 'snow'
@ -35,7 +37,11 @@ print_r($response->asArray());`,
}, },
iconType: 'php.svg', iconType: 'php.svg',
id: Languages.PHP, id: Languages.PHP,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToPHP(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToPHP(extraIngestDocumentValues) : '';
return `$params = [${ingestPipeline ? `\n 'pipeline' => '${ingestPipeline}',` : ''} return `$params = [${ingestPipeline ? `\n 'pipeline' => '${ingestPipeline}',` : ''}
'body' => [ 'body' => [

View file

@ -10,10 +10,13 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels';
import { docLinks } from '../../doc_links'; import { docLinks } from '../../doc_links';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToJSON } from './helpers'; import { ingestKeysToJSON } from './helpers';
export const pythonDefinition: LanguageDefinition = { export const pythonDefinition: LanguageDefinition = {
buildSearchQuery: ({ indexName }) => `client.search(index="${indexName}", q="snow")`, buildSearchQuery: ({ indexName = INDEX_NAME_PLACEHOLDER }) =>
`client.search(index="${indexName}", q="snow")`,
configureClient: ({ url, apiKey }) => `from elasticsearch import Elasticsearch configureClient: ({ url, apiKey }) => `from elasticsearch import Elasticsearch
client = Elasticsearch( client = Elasticsearch(
@ -29,7 +32,11 @@ client = Elasticsearch(
}, },
iconType: 'python.svg', iconType: 'python.svg',
id: Languages.PYTHON, id: Languages.PYTHON,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : '';
return `documents = [ return `documents = [
{ "index": { "_index": "${indexName}", "_id": "9780553351927"}}, { "index": { "_index": "${indexName}", "_id": "9780553351927"}},

View file

@ -10,10 +10,13 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels';
import { docLinks } from '../../doc_links'; import { docLinks } from '../../doc_links';
import { INDEX_NAME_PLACEHOLDER } from './constants';
import { ingestKeysToRuby } from './helpers'; import { ingestKeysToRuby } from './helpers';
export const rubyDefinition: LanguageDefinition = { export const rubyDefinition: LanguageDefinition = {
buildSearchQuery: ({ indexName }) => `client.search(index: '${indexName}', q: 'snow')`, buildSearchQuery: ({ indexName = INDEX_NAME_PLACEHOLDER }) =>
`client.search(index: '${indexName}', q: 'snow')`,
configureClient: ({ url, apiKey, cloudId }) => `client = Elasticsearch::Client.new( configureClient: ({ url, apiKey, cloudId }) => `client = Elasticsearch::Client.new(
api_key: '${apiKey}', api_key: '${apiKey}',
${cloudId ? `cloud_id: ${cloudId},` : `url: '${url}',`} ${cloudId ? `cloud_id: ${cloudId},` : `url: '${url}',`}
@ -28,7 +31,11 @@ export const rubyDefinition: LanguageDefinition = {
}, },
iconType: 'ruby.svg', iconType: 'ruby.svg',
id: Languages.RUBY, id: Languages.RUBY,
ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { ingestData: ({
indexName = INDEX_NAME_PLACEHOLDER,
ingestPipeline,
extraIngestDocumentValues,
}) => {
const ingestDocumentKeys = ingestPipeline ? ingestKeysToRuby(extraIngestDocumentValues) : ''; const ingestDocumentKeys = ingestPipeline ? ingestKeysToRuby(extraIngestDocumentValues) : '';
return `documents = [ return `documents = [
{ index: { _index: '${indexName}', data: {name: "Snow Crash", author: "Neal Stephenson", release_date: "1992-06-01", page_count: 470${ingestDocumentKeys}} } }, { index: { _index: '${indexName}', data: {name: "Snow Crash", author: "Neal Stephenson", release_date: "1992-06-01", page_count: 470${ingestDocumentKeys}} } },

View file

@ -37,8 +37,8 @@ export const AddDataPanelContent: React.FC<AddDataPanelContentProps> = ({
return ( return (
<CodeBox <CodeBox
languages={languageDefinitions} languages={languageDefinitions}
codeSnippet={getLanguageDefinitionCodeSnippet(selectedLanguage, 'testConnection', codeArgs)} codeSnippet={getLanguageDefinitionCodeSnippet(selectedLanguage, 'ingestData', codeArgs)}
consoleRequest={getConsoleRequest('testConnection')} consoleRequest={getConsoleRequest('ingestData')}
selectedLanguage={selectedLanguage} selectedLanguage={selectedLanguage}
setSelectedLanguage={setSelectedLanguage} setSelectedLanguage={setSelectedLanguage}
assetBasePath={assetBasePath} assetBasePath={assetBasePath}

View file

@ -9,6 +9,7 @@ import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { css } from '@emotion/react';
import { useValues, useActions } from 'kea'; import { useValues, useActions } from 'kea';
import { import {
@ -27,15 +28,13 @@ import {
EuiHorizontalRule, EuiHorizontalRule,
EuiButton, EuiButton,
EuiHeaderLinks, EuiHeaderLinks,
useEuiTheme,
} from '@elastic/eui'; } from '@elastic/eui';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react'; import { FormattedMessage } from '@kbn/i18n-react';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants'; import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants';
import { Status } from '../../../../common/types/api';
import { CreateApiKeyAPILogic } from '../../enterprise_search_overview/api/create_elasticsearch_api_key_logic';
import { FetchApiKeysAPILogic } from '../../enterprise_search_overview/api/fetch_api_keys_logic'; import { FetchApiKeysAPILogic } from '../../enterprise_search_overview/api/fetch_api_keys_logic';
import { CreateApiKeyFlyout } from '../api_key/create_api_key_flyout'; import { CreateApiKeyFlyout } from '../api_key/create_api_key_flyout';
import { KibanaLogic } from '../kibana'; import { KibanaLogic } from '../kibana';
@ -48,9 +47,7 @@ export const EndpointsHeaderAction: React.FC = ({ children }) => {
const { makeRequest } = useActions(FetchApiKeysAPILogic); const { makeRequest } = useActions(FetchApiKeysAPILogic);
const { data } = useValues(FetchApiKeysAPILogic); const { data } = useValues(FetchApiKeysAPILogic);
const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
const { user } = useValues(KibanaLogic); const { euiTheme } = useEuiTheme();
const { makeRequest: saveApiKey } = useActions(CreateApiKeyAPILogic);
const { data: apiKey, error, status } = useValues(CreateApiKeyAPILogic);
useEffect(() => makeRequest({}), []); useEffect(() => makeRequest({}), []);
@ -75,16 +72,7 @@ export const EndpointsHeaderAction: React.FC = ({ children }) => {
<EuiFlexGroup alignItems="center" gutterSize="s"> <EuiFlexGroup alignItems="center" gutterSize="s">
{Boolean(children) && <EuiFlexItem>{children}</EuiFlexItem>} {Boolean(children) && <EuiFlexItem>{children}</EuiFlexItem>}
<EuiFlexItem> <EuiFlexItem>
{isFlyoutOpen && ( {isFlyoutOpen && <CreateApiKeyFlyout onClose={() => setIsFlyoutOpen(false)} />}
<CreateApiKeyFlyout
createdApiKey={apiKey}
error={error?.body?.message}
isLoading={status === Status.LOADING}
onClose={() => setIsFlyoutOpen(false)}
setApiKey={saveApiKey}
username={user?.full_name || user?.username || ''}
/>
)}
<EuiPopover <EuiPopover
button={button} button={button}
isOpen={isPopoverOpen} isOpen={isPopoverOpen}
@ -93,6 +81,9 @@ export const EndpointsHeaderAction: React.FC = ({ children }) => {
anchorPosition="downLeft" anchorPosition="downLeft"
> >
<EuiContextMenuPanel <EuiContextMenuPanel
css={css`
max-width: calc(${euiTheme.size.xxxxl} * 4);
`}
items={[ items={[
<EuiContextMenuItem key="endpoint"> <EuiContextMenuItem key="endpoint">
<EuiText size="s"> <EuiText size="s">
@ -107,7 +98,13 @@ export const EndpointsHeaderAction: React.FC = ({ children }) => {
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="center"> <EuiFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="center">
<EuiFlexItem> <EuiFlexItem>
<EuiCode>{elasticsearchEndpoint}</EuiCode> <EuiCode
css={css`
overflow-wrap: anywhere;
`}
>
{elasticsearchEndpoint}
</EuiCode>
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<EuiCopy textToCopy={elasticsearchEndpoint || ''} afterMessage={COPIED_LABEL}> <EuiCopy textToCopy={elasticsearchEndpoint || ''} afterMessage={COPIED_LABEL}>
@ -139,7 +136,13 @@ export const EndpointsHeaderAction: React.FC = ({ children }) => {
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="center"> <EuiFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="center">
<EuiFlexItem> <EuiFlexItem>
<EuiCode>{cloudId}</EuiCode> <EuiCode
css={css`
overflow-wrap: anywhere;
`}
>
{cloudId}
</EuiCode>
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<EuiCopy textToCopy={cloudId || ''} afterMessage={COPIED_LABEL}> <EuiCopy textToCopy={cloudId || ''} afterMessage={COPIED_LABEL}>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB