Skip to content

Commit

Permalink
[Behavioral Analytics] Add api key modal in integration page (#154738)
Browse files Browse the repository at this point in the history
Add API Key modal to integration page.

<img width="812" alt="Screenshot 2023-04-11 at 16 13 40"
src="https://user-images.githubusercontent.com/49480/231208531-920272be-bd48-4bb0-971d-c740a2e8b2e2.png">
<img width="882" alt="Screenshot 2023-04-11 at 16 13 46"
src="https://user-images.githubusercontent.com/49480/231208527-d8fb2a41-ad9c-4fd3-b7c9-a1cd1de7fe02.png">
<img width="820" alt="Screenshot 2023-04-11 at 16 13 53"
src="https://user-images.githubusercontent.com/49480/231208520-e9ec8ae3-e3a7-4dc3-8e6b-f6f339e9f084.png">
<img width="991" alt="Screenshot 2023-04-11 at 16 13 59"
src="https://user-images.githubusercontent.com/49480/231208512-791f6a8c-e8ad-4960-840c-8a2bea5ab556.png">

---------

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
joemcelroy and kibanamachine authored Apr 12, 2023
1 parent 0790ec0 commit 57d6f41
Show file tree
Hide file tree
Showing 11 changed files with 783 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { mockHttpValues } from '../../../__mocks__/kea_logic';

import { nextTick } from '@kbn/test-jest-helpers';

import { generateAnalyticsApiKey } from './generate_analytics_api_key_logic';

describe('GenerateAnalyticsApiKeyLogic', () => {
const { http } = mockHttpValues;
beforeEach(() => {
jest.clearAllMocks();
});

describe('GenerateAnalyticsApiKeyLogic', () => {
it('calls correct api', async () => {
const promise = Promise.resolve({
apiKey: {
api_key: 'api_key',
encoded: 'encoded',
id: 'id',
name: 'name',
},
});
http.post.mockReturnValue(promise);
const result = generateAnalyticsApiKey({
collectionName: 'puggles',
keyName: 'puggles read only key',
});
await nextTick();
expect(http.post).toHaveBeenCalledWith(
'/internal/enterprise_search/analytics/collections/puggles/api_key',
{
body: JSON.stringify({
keyName: 'puggles read only key',
}),
}
);
await expect(result).resolves.toEqual({
apiKey: {
api_key: 'api_key',
encoded: 'encoded',
id: 'id',
name: 'name',
},
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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 { createApiLogic } from '../../../shared/api_logic/create_api_logic';
import { HttpLogic } from '../../../shared/http';

interface APIKeyResponse {
apiKey: {
api_key: string;
encoded: string;
id: string;
name: string;
};
}

export const generateAnalyticsApiKey = async ({
collectionName,
keyName,
}: {
collectionName: string;
keyName: string;
}) => {
const route = `/internal/enterprise_search/analytics/collections/${collectionName}/api_key`;

return await HttpLogic.values.http.post<APIKeyResponse>(route, {
body: JSON.stringify({
keyName,
}),
});
};

export const generateAnalyticsApiKeyLogic = createApiLogic(
['generate_analytics_api_key_logic'],
generateAnalyticsApiKey
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import '../../../../__mocks__/shallow_useeffect.mock';
import '../../../../__mocks__/kea_logic';

import React from 'react';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,39 @@
* 2.0.
*/

import React from 'react';

import { EuiSpacer, EuiSteps, EuiTab, EuiTabs } from '@elastic/eui';
import React, { useState } from 'react';

import { useValues } from 'kea';

import {
EuiButton,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiSteps,
EuiTab,
EuiTabs,
EuiLink,
EuiText,
} from '@elastic/eui';

import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';

import { i18n } from '@kbn/i18n';

import { AnalyticsCollection } from '../../../../../../common/types/analytics';
import { docLinks } from '../../../../shared/doc_links';

import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url';

import { KibanaLogic } from '../../../../shared/kibana';
import { EnterpriseSearchAnalyticsPageTemplate } from '../../layout/page_template';

import { javascriptClientEmbedSteps } from './analytics_collection_integrate_javascript_client_embed';
import { javascriptEmbedSteps } from './analytics_collection_integrate_javascript_embed';
import { searchUIEmbedSteps } from './analytics_collection_integrate_searchui';
import { GenerateAnalyticsApiKeyModal } from './api_key_modal/generate_analytics_api_key_modal';
import { GenerateApiKeyModalLogic } from './api_key_modal/generate_analytics_api_key_modal.logic';

interface AnalyticsCollectionIntegrateProps {
analyticsCollection: AnalyticsCollection;
Expand All @@ -35,13 +51,93 @@ export interface AnalyticsConfig {
endpoint: string;
}

const apiKeyStep = (
openApiKeyModal: () => void,
navigateToUrl: typeof KibanaLogic.values.navigateToUrl
): EuiContainedStepProps => ({
title: i18n.translate(
'xpack.enterpriseSearch.analytics.collections.collectionsView.apiKey.title',
{
defaultMessage: 'Create an API Key',
}
),
children: (
<>
<EuiText>
<p>
{i18n.translate(
'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.apiKeyWarning',
{
defaultMessage:
"Elastic does not store API keys. Once generated, you'll only be able to view the key one time. Make sure you save it somewhere secure. If you lose access to it you'll need to generate a new API key from this screen.",
}
)}{' '}
<EuiLink
href={docLinks.apiKeys}
data-telemetry-id="entSearchContent-analytics-apiKey-learnMoreLink"
external
target="_blank"
>
{i18n.translate(
'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.learnMoreLink',
{
defaultMessage: 'Learn more about API keys.',
}
)}
</EuiLink>
</p>
</EuiText>
<EuiSpacer size="l" />
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton
iconSide="left"
iconType="plusInCircleFilled"
onClick={openApiKeyModal}
data-telemetry-id="entSearchContent-analytics-apiKey-createApiKeyButton"
>
{i18n.translate(
'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.createAPIKeyButton',
{
defaultMessage: 'Create API Key',
}
)}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
iconSide="left"
iconType="popout"
data-telemetry-id="entSearchContent-analytics-apiKey-viewKeysButton"
onClick={() =>
navigateToUrl('/app/management/security/api_keys', {
shouldNotCreateHref: true,
})
}
>
{i18n.translate(
'xpack.enterpriseSearch.analytics.collectionsView.integration.apiKeyStep.viewKeysButton',
{
defaultMessage: 'View Keys',
}
)}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</>
),
});

export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionIntegrateProps> = ({
analyticsCollection,
}) => {
const [selectedTab, setSelectedTab] = React.useState<TabKey>('javascriptEmbed');
const [selectedTab, setSelectedTab] = useState<TabKey>('javascriptEmbed');
const [apiKeyModelOpen, setApiKeyModalOpen] = useState<boolean>(false);
const { navigateToUrl } = useValues(KibanaLogic);
const { apiKey } = useValues(GenerateApiKeyModalLogic);

const analyticsConfig: AnalyticsConfig = {
apiKey: '########',
apiKey: apiKey || '########',
collectionName: analyticsCollection?.name,
endpoint: getEnterpriseSearchUrl(),
};
Expand Down Expand Up @@ -80,9 +176,11 @@ export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionInteg
},
];

const apiKeyStepGuide = apiKeyStep(() => setApiKeyModalOpen(true), navigateToUrl);

const steps: Record<TabKey, EuiContainedStepProps[]> = {
javascriptClientEmbed: javascriptClientEmbedSteps(analyticsConfig),
javascriptEmbed: javascriptEmbedSteps(webClientSrc, analyticsConfig),
javascriptClientEmbed: [apiKeyStepGuide, ...javascriptClientEmbedSteps(analyticsConfig)],
javascriptEmbed: [apiKeyStepGuide, ...javascriptEmbedSteps(webClientSrc, analyticsConfig)],
searchuiEmbed: searchUIEmbedSteps(setSelectedTab),
};

Expand Down Expand Up @@ -111,6 +209,14 @@ export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionInteg
}}
>
<>
{apiKeyModelOpen ? (
<GenerateAnalyticsApiKeyModal
collectionName={analyticsCollection.name}
onClose={() => {
setApiKeyModalOpen(false);
}}
/>
) : null}
<EuiTabs>
{tabs.map((tab) => (
<EuiTab
Expand Down
Loading

0 comments on commit 57d6f41

Please sign in to comment.