mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Behavioral Analytics] Reinstate Integrations Page + Sub routes refactor (#154267)
## Highlights: - Now have sub-routes for collection view page. The base component is responsible for fetching the analytics collection and displaying an error state when analytics collection not found / deleted. - Integration page now present - remove unneeded section param in favour for the explicit route paths - removed the old "events" page --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
6eb2c5ed91
commit
95bc7c0e1c
21 changed files with 473 additions and 528 deletions
|
@ -24,7 +24,7 @@ import {
|
|||
AddAnalyticsCollectionApiLogicArgs,
|
||||
AddAnalyticsCollectionApiLogicResponse,
|
||||
} from '../../api/add_analytics_collection/add_analytics_collection_api_logic';
|
||||
import { COLLECTION_VIEW_PATH } from '../../routes';
|
||||
import { COLLECTION_OVERVIEW_PATH } from '../../routes';
|
||||
|
||||
const SERVER_ERROR_CODE = 500;
|
||||
|
||||
|
@ -102,7 +102,7 @@ export const AddAnalyticsCollectionLogic = kea<
|
|||
})
|
||||
);
|
||||
KibanaLogic.values.navigateToUrl(
|
||||
generateEncodedPath(COLLECTION_VIEW_PATH, {
|
||||
generateEncodedPath(COLLECTION_OVERVIEW_PATH, {
|
||||
name,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,71 +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 '../../../__mocks__/shallow_useeffect.mock';
|
||||
|
||||
import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { EuiEmptyPrompt } from '@elastic/eui';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../common/types/analytics';
|
||||
import { EntSearchLogStream } from '../../../shared/log_stream';
|
||||
|
||||
import { AnalyticsCollectionEvents } from './analytics_collection_events';
|
||||
|
||||
describe('AnalyticsCollectionEvents', () => {
|
||||
const analyticsCollection: AnalyticsCollection = {
|
||||
events_datastream: 'logs-elastic_analytics.events-example',
|
||||
name: 'example',
|
||||
};
|
||||
|
||||
const mockActions = {
|
||||
analyticsEventsIndexExists: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
setMockActions(mockActions);
|
||||
});
|
||||
|
||||
it('renders', () => {
|
||||
setMockValues({
|
||||
isPresent: true,
|
||||
isLoading: false,
|
||||
});
|
||||
const expectedQuery = '_index: logs-elastic_analytics.events-example';
|
||||
|
||||
const wrapper = shallow(<AnalyticsCollectionEvents collection={analyticsCollection} />);
|
||||
expect(wrapper.find(EntSearchLogStream).prop('query')).toEqual(expectedQuery);
|
||||
});
|
||||
|
||||
describe('empty state', () => {
|
||||
it('renders when analytics events index is not present', () => {
|
||||
setMockValues({
|
||||
isPresent: false,
|
||||
});
|
||||
|
||||
const wrapper = shallow(<AnalyticsCollectionEvents collection={analyticsCollection} />);
|
||||
|
||||
expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('renders when analytics events index check is not performed yet', () => {
|
||||
setMockValues({
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
const wrapper = shallow(<AnalyticsCollectionEvents collection={analyticsCollection} />);
|
||||
|
||||
expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,148 +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 React, { useEffect } from 'react';
|
||||
|
||||
import { useValues, useActions } from 'kea';
|
||||
|
||||
import { EuiEmptyPrompt, EuiButton, EuiLink, EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { ENTERPRISE_SEARCH_ANALYTICS_LOGS_SOURCE_ID } from '../../../../../common/constants';
|
||||
import { AnalyticsCollection } from '../../../../../common/types/analytics';
|
||||
import { docLinks } from '../../../shared/doc_links';
|
||||
import { generateEncodedPath } from '../../../shared/encode_path_params';
|
||||
import { KibanaLogic } from '../../../shared/kibana';
|
||||
|
||||
import { EntSearchLogStream } from '../../../shared/log_stream';
|
||||
import { COLLECTION_VIEW_PATH } from '../../routes';
|
||||
|
||||
import { AnalyticsEventsIndexExistsLogic } from './analytics_events_index_exists_logic';
|
||||
|
||||
interface AnalyticsCollectionEventsProps {
|
||||
collection: AnalyticsCollection;
|
||||
}
|
||||
|
||||
const EVENTS_POLLING_INTERVAL = 30 * 1000;
|
||||
|
||||
export const AnalyticsCollectionEvents: React.FC<AnalyticsCollectionEventsProps> = ({
|
||||
collection,
|
||||
}) => {
|
||||
const { analyticsEventsIndexExists } = useActions(AnalyticsEventsIndexExistsLogic);
|
||||
const { isLoading, isPresent } = useValues(AnalyticsEventsIndexExistsLogic);
|
||||
const { navigateToUrl } = useValues(KibanaLogic);
|
||||
|
||||
useEffect(() => {
|
||||
analyticsEventsIndexExists(collection.events_datastream);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
analyticsEventsIndexExists(collection.events_datastream);
|
||||
}, EVENTS_POLLING_INTERVAL);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(isLoading || !isPresent) && (
|
||||
<EuiEmptyPrompt
|
||||
iconType="visLine"
|
||||
title={
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.title"
|
||||
defaultMessage="{title}"
|
||||
values={{
|
||||
title: (
|
||||
<>
|
||||
There are no analytics events for <strong>{collection.name}</strong> yet
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
}
|
||||
body={i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.body',
|
||||
{
|
||||
defaultMessage:
|
||||
"Start tracking events by adding the behavioral analytics client to every page of your website or application that you'd like to track",
|
||||
}
|
||||
)}
|
||||
actions={
|
||||
<EuiButton
|
||||
color="primary"
|
||||
fill
|
||||
onClick={() =>
|
||||
navigateToUrl(
|
||||
generateEncodedPath(COLLECTION_VIEW_PATH, {
|
||||
id: collection.name,
|
||||
section: 'integrate',
|
||||
})
|
||||
)
|
||||
}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.actions',
|
||||
{
|
||||
defaultMessage: 'View integration instructions',
|
||||
}
|
||||
)}
|
||||
</EuiButton>
|
||||
}
|
||||
footer={
|
||||
<EuiLink href={docLinks.behavioralAnalytics} target="_blank">
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.footer',
|
||||
{
|
||||
defaultMessage: 'Visit the behavioral analytics documentation',
|
||||
}
|
||||
)}
|
||||
</EuiLink>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!isLoading && isPresent && (
|
||||
<EntSearchLogStream
|
||||
logView={{
|
||||
type: 'log-view-reference',
|
||||
logViewId: ENTERPRISE_SEARCH_ANALYTICS_LOGS_SOURCE_ID,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
type: 'timestamp',
|
||||
},
|
||||
{
|
||||
type: 'field',
|
||||
header: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.eventName',
|
||||
{
|
||||
defaultMessage: 'Event name',
|
||||
}
|
||||
),
|
||||
field: 'event.action',
|
||||
},
|
||||
{
|
||||
type: 'field',
|
||||
header: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.userUuid',
|
||||
{
|
||||
defaultMessage: 'User UUID',
|
||||
}
|
||||
),
|
||||
field: 'labels.user_uuid',
|
||||
},
|
||||
]}
|
||||
query={`_index: ${collection.events_datastream}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -9,12 +9,17 @@ import '../../../../__mocks__/shallow_useeffect.mock';
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { EuiCodeBlock } from '@elastic/eui';
|
||||
import { mountWithIntl } from '@kbn/test-jest-helpers';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { EuiCodeBlock, EuiSteps } from '@elastic/eui';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../../common/types/analytics';
|
||||
|
||||
import { AnalyticsCollectionIntegrate } from './analytics_collection_integrate';
|
||||
import { AnalyticsCollectionIntegrateView } from './analytics_collection_integrate_view';
|
||||
|
||||
jest.mock('../../../../shared/enterprise_search_url', () => ({
|
||||
getEnterpriseSearchUrl: () => 'http://localhost:3002',
|
||||
}));
|
||||
|
||||
describe('AnalyticsCollectionIntegrate', () => {
|
||||
const analyticsCollections: AnalyticsCollection = {
|
||||
|
@ -27,23 +32,31 @@ describe('AnalyticsCollectionIntegrate', () => {
|
|||
});
|
||||
|
||||
it('renders', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<AnalyticsCollectionIntegrate collection={analyticsCollections} />
|
||||
const wrapper = shallow(
|
||||
<AnalyticsCollectionIntegrateView analyticsCollection={analyticsCollections} />
|
||||
);
|
||||
expect(wrapper.find(EuiCodeBlock)).toHaveLength(3);
|
||||
expect(wrapper.find(EuiSteps).dive().find(EuiCodeBlock)).toHaveLength(3);
|
||||
wrapper.find('[data-test-subj="searchuiEmbed"]').at(0).simulate('click');
|
||||
expect(wrapper.find(EuiCodeBlock)).toHaveLength(3);
|
||||
expect(wrapper.find(EuiSteps).dive().find(EuiCodeBlock)).toHaveLength(3);
|
||||
wrapper.find('[data-test-subj="javascriptClientEmbed"]').at(0).simulate('click');
|
||||
expect(wrapper.find(EuiCodeBlock)).toHaveLength(5);
|
||||
expect(wrapper.find(EuiSteps).dive().find(EuiCodeBlock)).toHaveLength(5);
|
||||
});
|
||||
|
||||
it('check value of analyticsDNSUrl & webClientSrc', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<AnalyticsCollectionIntegrate collection={analyticsCollections} />
|
||||
it('check value of config & webClientSrc', () => {
|
||||
const wrapper = shallow(
|
||||
<AnalyticsCollectionIntegrateView analyticsCollection={analyticsCollections} />
|
||||
);
|
||||
expect(wrapper.find(EuiCodeBlock).at(0).text()).toContain(
|
||||
'data-dsn="/api/analytics/collections/example"'
|
||||
expect(wrapper.find(EuiSteps).dive().find(EuiCodeBlock).at(0).dive().text()).toContain(
|
||||
'https://cdn.jsdelivr.net/npm/@elastic/behavioral-analytics-browser-tracker@2/dist/umd/index.global.js'
|
||||
);
|
||||
expect(wrapper.find(EuiCodeBlock).at(0).text()).toContain('src="/analytics.js"');
|
||||
|
||||
expect(wrapper.find(EuiSteps).dive().find(EuiCodeBlock).at(1).dive().text())
|
||||
.toMatchInlineSnapshot(`
|
||||
"<script type=\\"text/javascript\\">window.elasticAnalytics.createTracker({
|
||||
endpoint: \\"http://localhost:3002\\",
|
||||
collectionName: \\"example\\",
|
||||
apiKey: \\"########\\"
|
||||
});</script>"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,107 +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 React from 'react';
|
||||
|
||||
import { EuiPanel, EuiSpacer, EuiSteps, EuiTab, EuiTabs, EuiTitle } from '@elastic/eui';
|
||||
|
||||
import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../../common/types/analytics';
|
||||
import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url';
|
||||
|
||||
import { javascriptClientEmbedSteps } from './analytics_collection_integrate_javascript_client_embed';
|
||||
import { javascriptEmbedSteps } from './analytics_collection_integrate_javascript_embed';
|
||||
import { searchUIEmbedSteps } from './analytics_collection_integrate_searchui';
|
||||
|
||||
interface AnalyticsCollectionIntegrateProps {
|
||||
collection: AnalyticsCollection;
|
||||
}
|
||||
|
||||
export type TabKey = 'javascriptEmbed' | 'searchuiEmbed' | 'javascriptClientEmbed';
|
||||
|
||||
export const AnalyticsCollectionIntegrate: React.FC<AnalyticsCollectionIntegrateProps> = ({
|
||||
collection,
|
||||
}) => {
|
||||
const analyticsDNSUrl = getEnterpriseSearchUrl(`/api/analytics/collections/${collection.name}`);
|
||||
const webClientSrc = getEnterpriseSearchUrl('/analytics.js');
|
||||
|
||||
const [selectedTab, setSelectedTab] = React.useState<TabKey>('javascriptEmbed');
|
||||
|
||||
const tabs: Array<{
|
||||
key: TabKey;
|
||||
title: string;
|
||||
}> = [
|
||||
{
|
||||
key: 'javascriptEmbed',
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.title',
|
||||
{
|
||||
defaultMessage: 'Javascript Embed',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'javascriptClientEmbed',
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.title',
|
||||
{
|
||||
defaultMessage: 'Javascript Client',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'searchuiEmbed',
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.title',
|
||||
{
|
||||
defaultMessage: 'Search UI',
|
||||
}
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const steps: Record<TabKey, EuiContainedStepProps[]> = {
|
||||
javascriptClientEmbed: javascriptClientEmbedSteps(analyticsDNSUrl),
|
||||
javascriptEmbed: javascriptEmbedSteps(webClientSrc, analyticsDNSUrl),
|
||||
searchuiEmbed: searchUIEmbedSteps(setSelectedTab),
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiPanel hasBorder paddingSize="l">
|
||||
<EuiTitle size="s">
|
||||
<h2>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.title',
|
||||
{
|
||||
defaultMessage: 'Start tracking events',
|
||||
}
|
||||
)}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiTabs>
|
||||
{tabs.map((tab) => (
|
||||
<EuiTab
|
||||
key={tab.key}
|
||||
onClick={() => {
|
||||
setSelectedTab(tab.key);
|
||||
}}
|
||||
isSelected={selectedTab === tab.key}
|
||||
data-test-subj={tab.key}
|
||||
data-telemetry-id={`entSearch-analytics-integrate-${tab.key}-tab`}
|
||||
>
|
||||
{tab.title}
|
||||
</EuiTab>
|
||||
))}
|
||||
</EuiTabs>
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiSteps steps={steps[selectedTab]} />
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
|
@ -11,7 +11,9 @@ import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const javascriptClientEmbedSteps = (analyticsDNSUrl: string) => [
|
||||
import { AnalyticsConfig } from './analytics_collection_integrate_view';
|
||||
|
||||
export const javascriptClientEmbedSteps = (analyticsConfig: AnalyticsConfig) => [
|
||||
{
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepOne.title',
|
||||
|
@ -60,7 +62,8 @@ export const javascriptClientEmbedSteps = (analyticsDNSUrl: string) => [
|
|||
{`import {
|
||||
createTracker,
|
||||
trackPageView,
|
||||
trackEvent,
|
||||
trackSearch,
|
||||
trackSearchClick
|
||||
} from "@elastic/behavioral-analytics-javascript-tracker";`}
|
||||
</EuiCodeBlock>
|
||||
</EuiText>
|
||||
|
@ -82,7 +85,7 @@ export const javascriptClientEmbedSteps = (analyticsDNSUrl: string) => [
|
|||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepThree.description',
|
||||
{
|
||||
defaultMessage:
|
||||
' Use createTracker method to initialize the tracker with your DSN. You will then be able to use the tracker to send events to Behavioral Analytics.',
|
||||
'Use createTracker method to initialize the tracker with your Configuration. You will then be able to use the tracker to send events to Behavioral Analytics.',
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
|
@ -97,7 +100,9 @@ export const javascriptClientEmbedSteps = (analyticsDNSUrl: string) => [
|
|||
</p>
|
||||
<EuiCodeBlock language="javascript" isCopyable>
|
||||
{`createTracker({
|
||||
dsn: "${analyticsDNSUrl}",
|
||||
endpoint: "${analyticsConfig.endpoint}",
|
||||
collectionName: "${analyticsConfig.collectionName}",
|
||||
apiKey: "${analyticsConfig.apiKey}"
|
||||
});`}
|
||||
</EuiCodeBlock>
|
||||
</EuiText>
|
||||
|
@ -108,7 +113,7 @@ export const javascriptClientEmbedSteps = (analyticsDNSUrl: string) => [
|
|||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.title',
|
||||
{
|
||||
defaultMessage: 'Dispatch Pageview and behavior events',
|
||||
defaultMessage: 'Dispatch Pageview and search behavior events',
|
||||
}
|
||||
),
|
||||
children: (
|
||||
|
@ -155,28 +160,41 @@ const SearchPage = (props) => {
|
|||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionThree',
|
||||
{
|
||||
defaultMessage:
|
||||
'You can also dispatch custom events to Behavioral Analytics by calling the trackEvent method.',
|
||||
'You can also use trackSearch and trackSearchClick to track what your customers are searching and clicking on in your application.',
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
<EuiCodeBlock language="javascript" isCopyable>
|
||||
{`// track a custom event in React
|
||||
import { trackEvent } from '@elastic/behavioral-analytics-javascript-tracker';
|
||||
{`
|
||||
import { trackSearch } from '@elastic/behavioral-analytics-javascript-tracker';
|
||||
|
||||
const ProductDetailPage = (props) => {
|
||||
const SearchResult = ({ hit }) => {
|
||||
|
||||
const clickHandler = () => {
|
||||
trackSearchClick({
|
||||
document: { id: hit.id, index: "products" },
|
||||
search: {
|
||||
query: "search term",
|
||||
filters: [],
|
||||
page: { current: 1, size: 10 },
|
||||
results: {
|
||||
items: [
|
||||
{ id: "123", index: "products" }
|
||||
],
|
||||
total_results: 10
|
||||
},
|
||||
sort: {
|
||||
name: "relevance",
|
||||
},
|
||||
search_application: "website",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Product detail page</h1>
|
||||
<input type="button" onClick={() => {
|
||||
trackEvent("click", {
|
||||
category: "product",
|
||||
action: "add_to_cart",
|
||||
label: "product_id",
|
||||
value: "123"
|
||||
})
|
||||
}} value="Add to Basket"/>
|
||||
</div>
|
||||
<a onClick={clickHandler}>
|
||||
<h2>{hit.title}</h2>
|
||||
</a>
|
||||
)
|
||||
}`}
|
||||
</EuiCodeBlock>
|
||||
|
|
|
@ -14,7 +14,9 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
|
||||
import { docLinks } from '../../../../shared/doc_links';
|
||||
|
||||
export const javascriptEmbedSteps = (webClientSrc: string, analyticsDNSUrl: string) => [
|
||||
import { AnalyticsConfig } from './analytics_collection_integrate_view';
|
||||
|
||||
export const javascriptEmbedSteps = (webClientSrc: string, analyticsConfig: AnalyticsConfig) => [
|
||||
{
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.stepOne.title',
|
||||
|
@ -35,7 +37,7 @@ export const javascriptEmbedSteps = (webClientSrc: string, analyticsDNSUrl: stri
|
|||
)}
|
||||
</p>
|
||||
<EuiCodeBlock language="html" isCopyable>
|
||||
{`<script src="${webClientSrc}" data-dsn="${analyticsDNSUrl}"></script>`}
|
||||
{`<script src="${webClientSrc}"></script>`}
|
||||
</EuiCodeBlock>
|
||||
</EuiText>
|
||||
</>
|
||||
|
@ -61,7 +63,11 @@ export const javascriptEmbedSteps = (webClientSrc: string, analyticsDNSUrl: stri
|
|||
)}
|
||||
</p>
|
||||
<EuiCodeBlock language="html" isCopyable>
|
||||
{'<script type="text/javascript">window.elasticAnalytics.createTracker();</script>'}
|
||||
{`<script type="text/javascript">window.elasticAnalytics.createTracker({
|
||||
endpoint: "${analyticsConfig.endpoint}",
|
||||
collectionName: "${analyticsConfig.collectionName}",
|
||||
apiKey: "${analyticsConfig.apiKey}"
|
||||
});</script>`}
|
||||
</EuiCodeBlock>
|
||||
</EuiText>
|
||||
</>
|
||||
|
@ -69,9 +75,9 @@ export const javascriptEmbedSteps = (webClientSrc: string, analyticsDNSUrl: stri
|
|||
},
|
||||
{
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepThree.title',
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.stepThree.title',
|
||||
{
|
||||
defaultMessage: 'Track individual events',
|
||||
defaultMessage: 'Track search events',
|
||||
}
|
||||
),
|
||||
children: (
|
||||
|
@ -80,7 +86,7 @@ export const javascriptEmbedSteps = (webClientSrc: string, analyticsDNSUrl: stri
|
|||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.stepThree.description"
|
||||
defaultMessage="Track individual events, like clicks, by calling the trackEvent method. {link}"
|
||||
defaultMessage="Track individual search events, like result clicks and searches, by using the trackSearch or trackSearchClick methods. {link}"
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink
|
||||
|
@ -102,11 +108,36 @@ export const javascriptEmbedSteps = (webClientSrc: string, analyticsDNSUrl: stri
|
|||
/>
|
||||
</p>
|
||||
<EuiCodeBlock language="javascript" isCopyable>
|
||||
{`window.elasticAnalytics.trackEvent("click", {
|
||||
category: "product",
|
||||
action: "add_to_cart",
|
||||
label: "product_id",
|
||||
value: "123"
|
||||
{`window.elasticAnalytics.trackSearch({
|
||||
search: {
|
||||
query: "laptop",
|
||||
filters: [
|
||||
{ field: "brand", value: ["apple"] },
|
||||
{ field: "price", value: ["1000-2000"] },
|
||||
],
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
},
|
||||
results: {
|
||||
items: [
|
||||
{
|
||||
document: {
|
||||
id: "123",
|
||||
index: "products",
|
||||
},
|
||||
page: {
|
||||
url: "http://my-website.com/products/123",
|
||||
},
|
||||
},
|
||||
],
|
||||
total_results: 100,
|
||||
},
|
||||
sort: {
|
||||
name: "relevance",
|
||||
},
|
||||
search_application: "website",
|
||||
}
|
||||
});`}
|
||||
</EuiCodeBlock>
|
||||
</EuiText>
|
||||
|
|
|
@ -12,7 +12,7 @@ import { EuiCodeBlock, EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { TabKey } from './analytics_collection_integrate';
|
||||
import { TabKey } from './analytics_collection_integrate_view';
|
||||
|
||||
export const searchUIEmbedSteps = (setSelectedTab: (tab: TabKey) => void) => [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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 { EuiSpacer, EuiSteps, EuiTab, EuiTabs } from '@elastic/eui';
|
||||
|
||||
import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../../common/types/analytics';
|
||||
|
||||
import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url';
|
||||
|
||||
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';
|
||||
|
||||
interface AnalyticsCollectionIntegrateProps {
|
||||
analyticsCollection: AnalyticsCollection;
|
||||
}
|
||||
|
||||
export type TabKey = 'javascriptEmbed' | 'searchuiEmbed' | 'javascriptClientEmbed';
|
||||
|
||||
export interface AnalyticsConfig {
|
||||
apiKey: string;
|
||||
collectionName: string;
|
||||
endpoint: string;
|
||||
}
|
||||
|
||||
export const AnalyticsCollectionIntegrateView: React.FC<AnalyticsCollectionIntegrateProps> = ({
|
||||
analyticsCollection,
|
||||
}) => {
|
||||
const [selectedTab, setSelectedTab] = React.useState<TabKey>('javascriptEmbed');
|
||||
|
||||
const analyticsConfig: AnalyticsConfig = {
|
||||
apiKey: '########',
|
||||
collectionName: analyticsCollection?.name,
|
||||
endpoint: getEnterpriseSearchUrl(),
|
||||
};
|
||||
const webClientSrc = `https://cdn.jsdelivr.net/npm/@elastic/behavioral-analytics-browser-tracker@2/dist/umd/index.global.js`;
|
||||
|
||||
const tabs: Array<{
|
||||
key: TabKey;
|
||||
title: string;
|
||||
}> = [
|
||||
{
|
||||
key: 'javascriptEmbed',
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.title',
|
||||
{
|
||||
defaultMessage: 'Javascript Embed',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'javascriptClientEmbed',
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.title',
|
||||
{
|
||||
defaultMessage: 'Javascript Client',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'searchuiEmbed',
|
||||
title: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.title',
|
||||
{
|
||||
defaultMessage: 'Search UI',
|
||||
}
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const steps: Record<TabKey, EuiContainedStepProps[]> = {
|
||||
javascriptClientEmbed: javascriptClientEmbedSteps(analyticsConfig),
|
||||
javascriptEmbed: javascriptEmbedSteps(webClientSrc, analyticsConfig),
|
||||
searchuiEmbed: searchUIEmbedSteps(setSelectedTab),
|
||||
};
|
||||
|
||||
return (
|
||||
<EnterpriseSearchAnalyticsPageTemplate
|
||||
restrictWidth
|
||||
pageChrome={[analyticsCollection?.name]}
|
||||
analyticsName={analyticsCollection?.name}
|
||||
pageViewTelemetry={`View Analytics Collection - integrate`}
|
||||
pageHeader={{
|
||||
bottomBorder: false,
|
||||
pageTitle: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collectionsView.integration.title',
|
||||
{
|
||||
defaultMessage: 'Tracker Integration',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collectionsView.integration.description',
|
||||
{
|
||||
defaultMessage:
|
||||
'Easily install our tracker on your search application to receive in depth analytics data. No search applications required.',
|
||||
}
|
||||
),
|
||||
rightSideItems: [],
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<EuiTabs>
|
||||
{tabs.map((tab) => (
|
||||
<EuiTab
|
||||
key={tab.key}
|
||||
onClick={() => {
|
||||
setSelectedTab(tab.key);
|
||||
}}
|
||||
isSelected={selectedTab === tab.key}
|
||||
data-test-subj={tab.key}
|
||||
data-telemetry-id={`entSearch-analytics-integrate-${tab.key}-tab`}
|
||||
>
|
||||
{tab.title}
|
||||
</EuiTab>
|
||||
))}
|
||||
</EuiTabs>
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiSteps steps={steps[selectedTab]} />
|
||||
</>
|
||||
</EnterpriseSearchAnalyticsPageTemplate>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 '../../../__mocks__/shallow_useeffect.mock';
|
||||
|
||||
import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic';
|
||||
import { mockUseParams } from '../../../__mocks__/react_router';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../common/types/analytics';
|
||||
import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template';
|
||||
|
||||
import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart';
|
||||
|
||||
import { AnalyticsCollectionOverview } from './analytics_collection_overview';
|
||||
|
||||
const mockValues = {
|
||||
analyticsCollection: {
|
||||
events_datastream: 'analytics-events-example',
|
||||
name: 'Analytics-Collection-1',
|
||||
} as AnalyticsCollection,
|
||||
searchSessionId: 'session-id',
|
||||
timeRange: {
|
||||
from: 'now-90d',
|
||||
to: 'now',
|
||||
},
|
||||
};
|
||||
|
||||
const mockActions = {
|
||||
fetchAnalyticsCollection: jest.fn(),
|
||||
fetchAnalyticsCollectionDataViewId: jest.fn(),
|
||||
setTimeRange: jest.fn(),
|
||||
};
|
||||
|
||||
describe('AnalyticsOverView', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
mockUseParams.mockReturnValue({ name: '1', section: 'settings' });
|
||||
});
|
||||
|
||||
it('renders with Data', async () => {
|
||||
const wrapper = shallow(
|
||||
<AnalyticsCollectionOverview analyticsCollection={mockValues.analyticsCollection} />
|
||||
);
|
||||
expect(wrapper.find(AnalyticsCollectionChartWithLens)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('sends correct telemetry page name for selected tab', async () => {
|
||||
setMockValues(mockValues);
|
||||
setMockActions(mockActions);
|
||||
|
||||
const wrapper = shallow(
|
||||
<AnalyticsCollectionOverview analyticsCollection={mockValues.analyticsCollection} />
|
||||
);
|
||||
|
||||
expect(wrapper.prop('pageViewTelemetry')).toBe('View Analytics Collection - Overview');
|
||||
});
|
||||
|
||||
it('render toolbar in pageHeader rightSideItems ', async () => {
|
||||
setMockValues({ ...mockValues, dataViewId: null });
|
||||
setMockActions(mockActions);
|
||||
|
||||
const wrapper = shallow(
|
||||
<AnalyticsCollectionOverview analyticsCollection={mockValues.analyticsCollection} />
|
||||
);
|
||||
|
||||
expect(
|
||||
wrapper?.find(EnterpriseSearchAnalyticsPageTemplate)?.prop('pageHeader')?.rightSideItems
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('render AnalyticsCollectionChartWithLens with collection', () => {
|
||||
setMockValues(mockValues);
|
||||
setMockActions(mockActions);
|
||||
|
||||
const wrapper = shallow(
|
||||
<AnalyticsCollectionOverview analyticsCollection={mockValues.analyticsCollection} />
|
||||
);
|
||||
expect(wrapper?.find(AnalyticsCollectionChartWithLens)).toHaveLength(1);
|
||||
expect(wrapper?.find(AnalyticsCollectionChartWithLens).props()).toEqual({
|
||||
dataViewQuery: 'analytics-events-example',
|
||||
id: 'analytics-collection-chart-Analytics-Collection-1',
|
||||
searchSessionId: 'session-id',
|
||||
setTimeRange: mockActions.setTimeRange,
|
||||
timeRange: {
|
||||
from: 'now-90d',
|
||||
to: 'now',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 { useActions, useValues } from 'kea';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../common/types/analytics';
|
||||
|
||||
import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template';
|
||||
|
||||
import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart';
|
||||
import { AnalyticsCollectionToolbar } from './analytics_collection_toolbar/analytics_collection_toolbar';
|
||||
import { AnalyticsCollectionToolbarLogic } from './analytics_collection_toolbar/analytics_collection_toolbar_logic';
|
||||
|
||||
interface AnalyticsCollectionOverviewProps {
|
||||
analyticsCollection: AnalyticsCollection;
|
||||
}
|
||||
|
||||
export const AnalyticsCollectionOverview: React.FC<AnalyticsCollectionOverviewProps> = ({
|
||||
analyticsCollection,
|
||||
}) => {
|
||||
const { setTimeRange } = useActions(AnalyticsCollectionToolbarLogic);
|
||||
const { timeRange, searchSessionId } = useValues(AnalyticsCollectionToolbarLogic);
|
||||
|
||||
return (
|
||||
<EnterpriseSearchAnalyticsPageTemplate
|
||||
restrictWidth
|
||||
pageChrome={[analyticsCollection?.name]}
|
||||
analyticsName={analyticsCollection?.name}
|
||||
pageViewTelemetry={`View Analytics Collection - Overview`}
|
||||
pageHeader={{
|
||||
bottomBorder: false,
|
||||
pageTitle: i18n.translate('xpack.enterpriseSearch.analytics.collectionsView.title', {
|
||||
defaultMessage: 'Overview',
|
||||
}),
|
||||
rightSideItems: [<AnalyticsCollectionToolbar />],
|
||||
}}
|
||||
>
|
||||
<AnalyticsCollectionChartWithLens
|
||||
id={'analytics-collection-chart-' + analyticsCollection.name}
|
||||
dataViewQuery={analyticsCollection.events_datastream}
|
||||
timeRange={timeRange}
|
||||
setTimeRange={setTimeRange}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
</EnterpriseSearchAnalyticsPageTemplate>
|
||||
);
|
||||
};
|
|
@ -14,13 +14,12 @@ import React from 'react';
|
|||
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { EuiEmptyPrompt } from '@elastic/eui';
|
||||
|
||||
import { AnalyticsCollection } from '../../../../../common/types/analytics';
|
||||
import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template';
|
||||
|
||||
import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart';
|
||||
|
||||
import { AnalyticsCollectionIntegrate } from './analytics_collection_integrate/analytics_collection_integrate';
|
||||
import { AnalyticsCollectionSettings } from './analytics_collection_settings';
|
||||
import { AnalyticsCollectionIntegrateView } from './analytics_collection_integrate/analytics_collection_integrate_view';
|
||||
|
||||
import { AnalyticsCollectionView } from './analytics_collection_view';
|
||||
|
||||
|
@ -29,11 +28,6 @@ const mockValues = {
|
|||
events_datastream: 'analytics-events-example',
|
||||
name: 'Analytics-Collection-1',
|
||||
} as AnalyticsCollection,
|
||||
searchSessionId: 'session-id',
|
||||
timeRange: {
|
||||
from: 'now-90d',
|
||||
to: 'now',
|
||||
},
|
||||
};
|
||||
|
||||
const mockActions = {
|
||||
|
@ -46,7 +40,7 @@ describe('AnalyticsView', () => {
|
|||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
mockUseParams.mockReturnValue({ name: '1', section: 'settings' });
|
||||
mockUseParams.mockReturnValue({ name: '1' });
|
||||
});
|
||||
|
||||
it('renders when analytics collection is empty on initial query', () => {
|
||||
|
@ -59,54 +53,18 @@ describe('AnalyticsView', () => {
|
|||
|
||||
expect(mockActions.fetchAnalyticsCollection).toHaveBeenCalled();
|
||||
|
||||
expect(wrapper.find(AnalyticsCollectionSettings)).toHaveLength(0);
|
||||
expect(wrapper.find(AnalyticsCollectionIntegrate)).toHaveLength(0);
|
||||
expect(wrapper.find(AnalyticsCollectionIntegrateView)).toHaveLength(0);
|
||||
expect(wrapper.find(EnterpriseSearchAnalyticsPageTemplate)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('renders with Data', async () => {
|
||||
setMockValues(mockValues);
|
||||
setMockActions(mockActions);
|
||||
|
||||
shallow(<AnalyticsCollectionView />);
|
||||
|
||||
expect(mockActions.fetchAnalyticsCollection).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sends correct telemetry page name for selected tab', async () => {
|
||||
setMockValues(mockValues);
|
||||
it('render deleted state for deleted analytics collection', async () => {
|
||||
setMockValues({ ...mockValues, analyticsCollection: null });
|
||||
setMockActions(mockActions);
|
||||
|
||||
const wrapper = shallow(<AnalyticsCollectionView />);
|
||||
|
||||
expect(wrapper.prop('pageViewTelemetry')).toBe('View Analytics Collection - settings');
|
||||
});
|
||||
|
||||
it('render toolbar in pageHeader rightSideItems ', async () => {
|
||||
setMockValues({ ...mockValues, dataViewId: null });
|
||||
setMockActions(mockActions);
|
||||
|
||||
const wrapper = shallow(<AnalyticsCollectionView />);
|
||||
|
||||
expect(
|
||||
wrapper?.find(EnterpriseSearchAnalyticsPageTemplate)?.prop('pageHeader')?.rightSideItems
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('render AnalyticsCollectionChartWithLens with collection', () => {
|
||||
setMockValues(mockValues);
|
||||
setMockActions(mockActions);
|
||||
|
||||
const wrapper = shallow(<AnalyticsCollectionView />);
|
||||
expect(wrapper?.find(AnalyticsCollectionChartWithLens)).toHaveLength(1);
|
||||
expect(wrapper?.find(AnalyticsCollectionChartWithLens).props()).toEqual({
|
||||
dataViewQuery: 'analytics-events-example',
|
||||
id: 'analytics-collection-chart-Analytics-Collection-1',
|
||||
searchSessionId: 'session-id',
|
||||
setTimeRange: mockActions.setTimeRange,
|
||||
timeRange: {
|
||||
from: 'now-90d',
|
||||
to: 'now',
|
||||
},
|
||||
});
|
||||
expect(wrapper?.find(EnterpriseSearchAnalyticsPageTemplate).find(EuiEmptyPrompt)).toHaveLength(
|
||||
1
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,84 +7,80 @@
|
|||
|
||||
import React, { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Switch } from 'react-router-dom';
|
||||
|
||||
import { useActions, useValues } from 'kea';
|
||||
|
||||
import { EuiEmptyPrompt } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Route } from '@kbn/shared-ux-router';
|
||||
|
||||
import {
|
||||
COLLECTION_EXPLORER_PATH,
|
||||
COLLECTION_INTEGRATE_PATH,
|
||||
COLLECTION_OVERVIEW_PATH,
|
||||
} from '../../routes';
|
||||
import { AddAnalyticsCollection } from '../add_analytics_collections/add_analytics_collection';
|
||||
|
||||
import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template';
|
||||
|
||||
import { AnalyticsCollectionChartWithLens } from './analytics_collection_chart';
|
||||
import { AnalyticsCollectionToolbar } from './analytics_collection_toolbar/analytics_collection_toolbar';
|
||||
import { AnalyticsCollectionToolbarLogic } from './analytics_collection_toolbar/analytics_collection_toolbar_logic';
|
||||
import { AnalyticsCollectionIntegrateView } from './analytics_collection_integrate/analytics_collection_integrate_view';
|
||||
import { AnalyticsCollectionOverview } from './analytics_collection_overview';
|
||||
|
||||
import { FetchAnalyticsCollectionLogic } from './fetch_analytics_collection_logic';
|
||||
|
||||
export const AnalyticsCollectionView: React.FC = () => {
|
||||
const { fetchAnalyticsCollection } = useActions(FetchAnalyticsCollectionLogic);
|
||||
const { setTimeRange } = useActions(AnalyticsCollectionToolbarLogic);
|
||||
const { analyticsCollection, isLoading } = useValues(FetchAnalyticsCollectionLogic);
|
||||
const { timeRange, searchSessionId } = useValues(AnalyticsCollectionToolbarLogic);
|
||||
const { name, section } = useParams<{ name: string; section: string }>();
|
||||
const { name } = useParams<{ name: string }>();
|
||||
|
||||
useEffect(() => {
|
||||
fetchAnalyticsCollection(name);
|
||||
}, []);
|
||||
|
||||
if (analyticsCollection) {
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path={COLLECTION_OVERVIEW_PATH}>
|
||||
<AnalyticsCollectionOverview analyticsCollection={analyticsCollection} />
|
||||
</Route>
|
||||
|
||||
<Route exact path={COLLECTION_INTEGRATE_PATH}>
|
||||
<AnalyticsCollectionIntegrateView analyticsCollection={analyticsCollection} />
|
||||
</Route>
|
||||
|
||||
<Route exact path={COLLECTION_EXPLORER_PATH} />
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EnterpriseSearchAnalyticsPageTemplate
|
||||
restrictWidth
|
||||
isLoading={isLoading}
|
||||
pageChrome={[analyticsCollection?.name]}
|
||||
analyticsName={analyticsCollection?.name}
|
||||
pageViewTelemetry={`View Analytics Collection - ${section}`}
|
||||
pageHeader={{
|
||||
bottomBorder: false,
|
||||
pageTitle: i18n.translate('xpack.enterpriseSearch.analytics.collectionsView.title', {
|
||||
defaultMessage: 'Overview',
|
||||
}),
|
||||
rightSideItems: [<AnalyticsCollectionToolbar />],
|
||||
}}
|
||||
>
|
||||
{analyticsCollection ? (
|
||||
<AnalyticsCollectionChartWithLens
|
||||
id={'analytics-collection-chart-' + analyticsCollection.name}
|
||||
dataViewQuery={analyticsCollection.events_datastream}
|
||||
timeRange={timeRange}
|
||||
setTimeRange={setTimeRange}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
) : (
|
||||
<EuiEmptyPrompt
|
||||
iconType="search"
|
||||
title={
|
||||
<h2>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.headingTitle',
|
||||
{
|
||||
defaultMessage: 'You may have deleted this analytics collection',
|
||||
}
|
||||
)}
|
||||
</h2>
|
||||
}
|
||||
body={
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.subHeading',
|
||||
{
|
||||
defaultMessage:
|
||||
'An analytics collection provides a place to store the analytics events for any given search application you are building. Create a new collection to get started.',
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
actions={[<AddAnalyticsCollection />]}
|
||||
/>
|
||||
)}
|
||||
<EnterpriseSearchAnalyticsPageTemplate pageChrome={[]} restrictWidth isLoading={isLoading}>
|
||||
<EuiEmptyPrompt
|
||||
iconType="search"
|
||||
title={
|
||||
<h2>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.headingTitle',
|
||||
{
|
||||
defaultMessage: 'You may have deleted this analytics collection',
|
||||
}
|
||||
)}
|
||||
</h2>
|
||||
}
|
||||
body={
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.subHeading',
|
||||
{
|
||||
defaultMessage:
|
||||
'An analytics collection provides a place to store the analytics events for any given search application you are building. Create a new collection to get started.',
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
actions={[<AddAnalyticsCollection />]}
|
||||
/>
|
||||
</EnterpriseSearchAnalyticsPageTemplate>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ import { generateEncodedPath } from '../../../../shared/encode_path_params';
|
|||
|
||||
import { KibanaLogic } from '../../../../shared/kibana';
|
||||
import { withLensData } from '../../../hoc/with_lens_data';
|
||||
import { COLLECTION_VIEW_PATH } from '../../../routes';
|
||||
import { COLLECTION_OVERVIEW_PATH } from '../../../routes';
|
||||
|
||||
import { FilterBy, getFormulaByFilter } from '../../../utils/get_formula_by_filter';
|
||||
|
||||
|
@ -102,7 +102,7 @@ export const AnalyticsCollectionCard: React.FC<
|
|||
const cardStyles = AnalyticsCollectionCardStyles(euiTheme);
|
||||
const status = getChartStatus(secondaryMetric);
|
||||
const CARD_THEME = getCardTheme(euiTheme)[status];
|
||||
const collectionViewUrl = generateEncodedPath(COLLECTION_VIEW_PATH, {
|
||||
const collectionViewUrl = generateEncodedPath(COLLECTION_OVERVIEW_PATH, {
|
||||
name: collection.name,
|
||||
});
|
||||
const handleCardClick = (event: MouseEvent) => {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry';
|
|||
import {
|
||||
COLLECTION_EXPLORER_PATH,
|
||||
COLLECTION_INTEGRATE_PATH,
|
||||
COLLECTION_VIEW_PATH,
|
||||
COLLECTION_OVERVIEW_PATH,
|
||||
} from '../../routes';
|
||||
|
||||
interface EnterpriseSearchAnalyticsPageTemplateProps extends PageTemplateProps {
|
||||
|
@ -41,7 +41,7 @@ export const EnterpriseSearchAnalyticsPageTemplate: React.FC<
|
|||
integration: generateEncodedPath(COLLECTION_INTEGRATE_PATH, {
|
||||
name: analyticsName,
|
||||
}),
|
||||
overview: generateEncodedPath(COLLECTION_VIEW_PATH, {
|
||||
overview: generateEncodedPath(COLLECTION_OVERVIEW_PATH, {
|
||||
name: analyticsName,
|
||||
}),
|
||||
}
|
||||
|
|
|
@ -17,12 +17,7 @@ import { VersionMismatchPage } from '../shared/version_mismatch';
|
|||
import { AnalyticsCollectionView } from './components/analytics_collection_view/analytics_collection_view';
|
||||
import { AnalyticsOverview } from './components/analytics_overview/analytics_overview';
|
||||
|
||||
import {
|
||||
ROOT_PATH,
|
||||
COLLECTION_VIEW_PATH,
|
||||
COLLECTION_INTEGRATE_PATH,
|
||||
COLLECTION_EXPLORER_PATH,
|
||||
} from './routes';
|
||||
import { ROOT_PATH, COLLECTION_VIEW_PATH } from './routes';
|
||||
|
||||
export const Analytics: React.FC<InitialAppData> = (props) => {
|
||||
const { enterpriseSearchVersion, kibanaVersion } = props;
|
||||
|
@ -40,13 +35,9 @@ export const Analytics: React.FC<InitialAppData> = (props) => {
|
|||
<AnalyticsOverview />
|
||||
)}
|
||||
</Route>
|
||||
<Route exact path={COLLECTION_VIEW_PATH}>
|
||||
<Route path={COLLECTION_VIEW_PATH}>
|
||||
<AnalyticsCollectionView />
|
||||
</Route>
|
||||
|
||||
<Route exact path={COLLECTION_INTEGRATE_PATH} />
|
||||
|
||||
<Route exact path={COLLECTION_EXPLORER_PATH} />
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
export const ROOT_PATH = '/';
|
||||
export const COLLECTIONS_PATH = '/collections';
|
||||
export const COLLECTION_VIEW_PATH = `${COLLECTIONS_PATH}/:name/overview`;
|
||||
export const COLLECTION_INTEGRATE_PATH = `${COLLECTIONS_PATH}/:name/integrate`;
|
||||
export const COLLECTION_EXPLORER_PATH = `${COLLECTIONS_PATH}/:name/explorer`;
|
||||
export const COLLECTION_VIEW_PATH = `${COLLECTIONS_PATH}/:name`;
|
||||
export const COLLECTION_OVERVIEW_PATH = `${COLLECTION_VIEW_PATH}/overview`;
|
||||
export const COLLECTION_INTEGRATE_PATH = `${COLLECTION_VIEW_PATH}/integrate`;
|
||||
export const COLLECTION_EXPLORER_PATH = `${COLLECTION_VIEW_PATH}/explorer`;
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { ANALYTICS_PLUGIN } from '../../../../../../common/constants';
|
||||
import { COLLECTION_VIEW_PATH } from '../../../../analytics/routes';
|
||||
import { COLLECTION_INTEGRATE_PATH } from '../../../../analytics/routes';
|
||||
import { docLinks } from '../../../../shared/doc_links';
|
||||
import { generateEncodedPath } from '../../../../shared/encode_path_params';
|
||||
import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url';
|
||||
|
@ -165,9 +165,8 @@ export const EngineAPI: React.FC = () => {
|
|||
data-telemetry-id="entSearchContent-engines-api-step4-learnHowLink"
|
||||
onClick={() =>
|
||||
navigateToUrl(
|
||||
generateEncodedPath(`${ANALYTICS_PLUGIN.URL}${COLLECTION_VIEW_PATH}`, {
|
||||
generateEncodedPath(`${ANALYTICS_PLUGIN.URL}${COLLECTION_INTEGRATE_PATH}`, {
|
||||
id: engineName,
|
||||
section: 'integrate',
|
||||
}),
|
||||
{ shouldNotCreateHref: true }
|
||||
)
|
||||
|
|
|
@ -11104,7 +11104,6 @@
|
|||
"xpack.embeddableEnhanced.actions.panelNotifications.manyDrilldowns": "Le panneau comporte {count} explorations",
|
||||
"xpack.embeddableEnhanced.actions.panelNotifications.oneDrilldown": "Le panneau comporte 1 recherche",
|
||||
"xpack.embeddableEnhanced.Drilldowns": "Explorations",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.title": "{title}",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.stepThree.description": "Suivez des événements individuels, tels que les clics, en appelant la méthode trackEvent. {link}",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepOne.description": "Suivez les instructions pour incorporer Behavioral Analytics dans votre site via {embedLink} ou {clientLink}.",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.moreInfoDescription": "Pour en savoir plus sur l'initialisation du suivi et le déclenchement d'événements, consultez {link}.",
|
||||
|
@ -11379,11 +11378,6 @@
|
|||
"xpack.enterpriseSearch.actionsHeader": "Actions",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.headingTitle": "Vous avez peut-être supprimé cette collection d'analyses",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.subHeading": "Une collection d'analyse permet de stocker les événements d'analyse pour toute application de recherche que vous créez. Créez une nouvelle collection pour commencer.",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.eventName": "Nom de l'événement",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.userUuid": "UUID d'utilisateur",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.actions": "Afficher les instructions de l'intégration",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.body": "Commencer à suivre les événements en ajoutant le client d'analyse comportementale à chaque page de votre site web ou de l'application que vous souhaitez suivre",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.footer": "Visiter la documentation relative à l'analyse comportementale",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.description": "Une fois que vous avez appelé createTracker, vous pouvez utiliser les méthodes de suivi telles que trackPageView pour envoyer les événements vers Behavioral Analytics.",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionThree": "Vous pouvez également déployer des événements personnalisés dans Behavioral Analytics en appelant la méthode trackEvent.",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionTwo": "Une fois initialisé, vous aurez la possibilité de suivre les vues de page dans votre application.",
|
||||
|
@ -11409,10 +11403,8 @@
|
|||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.importDescription": "Puis importez le plug-in Behavioral Analytics dans votre application.",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.setupDescription": "Enfin, ajoutez le plug-in dans la configuration Search UI. Selon la façon dont vous avez incorporé Behavioral Analytics, vous devrez peut-être transmettre le client. L'exemple ci-dessous montre comment transmettre le client lorsque le client Javascript est utilisé.",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepOne.title": "Incorporer Behavioral Analytics",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepThree.title": "Suivre les événements individuels",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepTwo.title": "Installer le plug-in Behavioral Analytics Search UI",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.title": "Search UI",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.title": "Commencer à suivre les événements",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.buttonTitle": "Supprimer cette collection",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.headingTitle": "Supprimer cette collection d'analyses",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.warning": "Cette action est irréversible",
|
||||
|
|
|
@ -11103,7 +11103,6 @@
|
|||
"xpack.embeddableEnhanced.actions.panelNotifications.manyDrilldowns": "パネルには{count}個のドリルダウンがあります",
|
||||
"xpack.embeddableEnhanced.actions.panelNotifications.oneDrilldown": "パネルには 1 個のドリルダウンがあります",
|
||||
"xpack.embeddableEnhanced.Drilldowns": "ドリルダウン",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.title": "{title}",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.stepThree.description": "trackEventメソッドを呼び出し、クリックなどの個別のイベントを追跡します。{link}",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepOne.description": "指示に従って、{embedLink}または{clientLink}からサイトに行動分析を組み込んでください。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.moreInfoDescription": "トラッカーの初期化およびイベントの発生については、{link}を参照してください。",
|
||||
|
@ -11378,11 +11377,6 @@
|
|||
"xpack.enterpriseSearch.actionsHeader": "アクション",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.headingTitle": "この分析コレクションを削除した可能性があります",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.subHeading": "分析コレクションには、構築している特定の検索アプリケーションの分析イベントを格納できます。開始するには、新しいコレクションを作成してください。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.eventName": "イベント名",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.userUuid": "ユーザーUUID",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.actions": "統合手順を表示",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.body": "追跡したいWebサイトやアプリケーションの各ページに行動分析クライアントを追加して、イベントの追跡を開始します。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.footer": "行動分析ドキュメントを表示",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.description": "createTrackerを呼び出したら、trackPageViewなどのtrackerメソッドを使って、Behavioral Analyticsにイベントを送ることができます。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionThree": "また、trackEventメソッドを呼び出すことで、Behavioral Analyticsにカスタムイベントをディスパッチすることもできます。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionTwo": "初期化すると、アプリケーションのページビューを追跡することができるようになります。",
|
||||
|
@ -11408,10 +11402,8 @@
|
|||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.importDescription": "Behavioral Analyticsプラグインをアプリにインポートします。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.setupDescription": "最後に、プラグインをSearch UI構成に追加します。Behavioral Analyticsをどのように組み込んだかによって、クライアントを渡す必要がある場合があります。以下の例では、Javascriptクライアントを使用する場合の受け渡し方法を示しています。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepOne.title": "Behavioral Analyticsを組み込み",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepThree.title": "個別のイベントを追跡",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepTwo.title": "Search UI行動分析プラグインをインストール",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.title": "Search UI",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.title": "追跡イベントの開始",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.buttonTitle": "このコレクションを削除",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.headingTitle": "この分析コレクションを削除",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.warning": "この操作は元に戻すことができません",
|
||||
|
|
|
@ -11104,7 +11104,6 @@
|
|||
"xpack.embeddableEnhanced.actions.panelNotifications.manyDrilldowns": "面板有 {count} 个向下钻取",
|
||||
"xpack.embeddableEnhanced.actions.panelNotifications.oneDrilldown": "面板有 1 个向下钻取",
|
||||
"xpack.embeddableEnhanced.Drilldowns": "向下钻取",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.title": "{title}",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptEmbed.stepThree.description": "通过调用 trackEvent 方法跟踪单个事件,如点击。{link}",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepOne.description": "按照说明通过 {embedLink} 或 {clientLink} 将行为分析嵌入到您的站点中。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.moreInfoDescription": "请参阅 {link} 了解有关初始化跟踪器和触发事件的更多信息。",
|
||||
|
@ -11379,11 +11378,6 @@
|
|||
"xpack.enterpriseSearch.actionsHeader": "操作",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.headingTitle": "您可能已删除此分析集合",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.collectionNotFoundState.subHeading": "分析集合为您正在构建的任何给定搜索应用程序提供了一个用于存储分析事件的位置。创建新集合以开始。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.eventName": "事件名称",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.columns.userUuid": "用户 UUID",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.actions": "查看集成说明",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.body": "通过将行为分析客户端添加到您要跟踪的每个网站页面或应用程序来启动事件跟踪",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.eventsTab.emptyState.footer": "访问行为分析文档",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.description": "调用 createTracker 后,可以使用跟踪器方法(如 trackPageView)将事件发送到行为分析。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionThree": "还可以通过调用 trackEvent 方法来向行为分析分派定制事件。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.javascriptClientEmbed.stepFour.descriptionTwo": "完成初始化后,您将能够跟踪您应用程序中的页面视图。",
|
||||
|
@ -11409,10 +11403,8 @@
|
|||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.importDescription": "然后将行为分析插件导入到您的应用。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchui.stepTwo.setupDescription": "最后,将插件添加到搜索 UI 配置。根据您嵌入行为分析的方式,您可能需要传入客户端。以下示例说明如何在使用 Javascript 客户端时传入客户端。",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepOne.title": "嵌入行为分析",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepThree.title": "跟踪单个事件",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.stepTwo.title": "安装搜索 UI 行为分析插件",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.searchuiEmbed.title": "搜索 UI",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.integrateTab.title": "开始跟踪事件",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.buttonTitle": "删除此集合",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.headingTitle": "删除此分析集合",
|
||||
"xpack.enterpriseSearch.analytics.collections.collectionsView.settingsTab.delete.warning": "此操作不可逆",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue