[8.18] [Synonyms] Update Synonyms Text and Enable (#215618) (#215833)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[Synonyms] Update Synonyms Text and Enable
(#215618)](https://github.com/elastic/kibana/pull/215618)

<!--- Backport version: 9.6.6 -->

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

<!--BACKPORT [{"author":{"name":"Efe Gürkan
YALAMAN","email":"efeguerkan.yalaman@elastic.co"},"sourceCommit":{"committedDate":"2025-03-24T23:30:55Z","message":"[Synonyms]
Update Synonyms Text and Enable (#215618)\n\n## Summary\n\nText in
various places updated.\nAdded some telemetry that was decided.\nSmall
visual changes on empty prompt page.\nAdded a new example in a
collapsible accordion.\nAlso enables the synonyms plugin by
default.\n\n<img width=\"1637\" alt=\"Screenshot 2025-03-24 at 10 36
26\"\nsrc=\"https://github.com/user-attachments/assets/b02ef4a7-a18f-44b5-a845-d2566102e8ea\"\n/>\n<img
width=\"1627\" alt=\"Screenshot 2025-03-24 at 10 36
40\"\nsrc=\"https://github.com/user-attachments/assets/f7ea1c5e-d82e-497a-b215-5eab7190f041\"\n/>\n<img
width=\"1634\" alt=\"Screenshot 2025-03-24 at 10 36
52\"\nsrc=\"https://github.com/user-attachments/assets/d410bcc1-c075-4b5a-bcb7-11f97c64ffb9\"\n/>\n<img
width=\"825\" alt=\"Screenshot 2025-03-24 at 10 37
00\"\nsrc=\"https://github.com/user-attachments/assets/8a9e7567-5dbd-4238-8f8b-297b78a4dcac\"\n/>\n\n\n\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] Any text
added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [ ] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] The PR description includes the
appropriate Release Notes section,\nand the correct `release_note:*`
label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"01a4ff72e73c1d31b0aeed76f3a9ec4b5393deb8","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","backport:version","v9.1.0","v8.19.0","v8.18.1","v9.0.1"],"title":"[Synonyms]
Update Synonyms Text and
Enable","number":215618,"url":"https://github.com/elastic/kibana/pull/215618","mergeCommit":{"message":"[Synonyms]
Update Synonyms Text and Enable (#215618)\n\n## Summary\n\nText in
various places updated.\nAdded some telemetry that was decided.\nSmall
visual changes on empty prompt page.\nAdded a new example in a
collapsible accordion.\nAlso enables the synonyms plugin by
default.\n\n<img width=\"1637\" alt=\"Screenshot 2025-03-24 at 10 36
26\"\nsrc=\"https://github.com/user-attachments/assets/b02ef4a7-a18f-44b5-a845-d2566102e8ea\"\n/>\n<img
width=\"1627\" alt=\"Screenshot 2025-03-24 at 10 36
40\"\nsrc=\"https://github.com/user-attachments/assets/f7ea1c5e-d82e-497a-b215-5eab7190f041\"\n/>\n<img
width=\"1634\" alt=\"Screenshot 2025-03-24 at 10 36
52\"\nsrc=\"https://github.com/user-attachments/assets/d410bcc1-c075-4b5a-bcb7-11f97c64ffb9\"\n/>\n<img
width=\"825\" alt=\"Screenshot 2025-03-24 at 10 37
00\"\nsrc=\"https://github.com/user-attachments/assets/8a9e7567-5dbd-4238-8f8b-297b78a4dcac\"\n/>\n\n\n\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] Any text
added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [ ] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] The PR description includes the
appropriate Release Notes section,\nand the correct `release_note:*`
label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"01a4ff72e73c1d31b0aeed76f3a9ec4b5393deb8"}},"sourceBranch":"main","suggestedTargetBranches":["8.x","8.18"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/215814","number":215814,"state":"MERGED","mergeCommit":{"sha":"5f3a62c004a3ea2a4879b9bc3f82e3ae5f02f4b0","message":"[9.0]
[Synonyms] Update Synonyms Text and Enable (#215618) (#215814)\n\n#
Backport\n\nThis will backport the following commits from `main` to
`9.0`:\n- [[Synonyms] Update Synonyms Text and
Enable\n(#215618)](https://github.com/elastic/kibana/pull/215618)\n\n\n\n###
Questions ?\nPlease refer to the [Backport
tool\ndocumentation](https://github.com/sorenlouv/backport)\n\n\n\nCo-authored-by:
Efe Gürkan YALAMAN
<efeguerkan.yalaman@elastic.co>"}},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/215618","number":215618,"mergeCommit":{"message":"[Synonyms]
Update Synonyms Text and Enable (#215618)\n\n## Summary\n\nText in
various places updated.\nAdded some telemetry that was decided.\nSmall
visual changes on empty prompt page.\nAdded a new example in a
collapsible accordion.\nAlso enables the synonyms plugin by
default.\n\n<img width=\"1637\" alt=\"Screenshot 2025-03-24 at 10 36
26\"\nsrc=\"https://github.com/user-attachments/assets/b02ef4a7-a18f-44b5-a845-d2566102e8ea\"\n/>\n<img
width=\"1627\" alt=\"Screenshot 2025-03-24 at 10 36
40\"\nsrc=\"https://github.com/user-attachments/assets/f7ea1c5e-d82e-497a-b215-5eab7190f041\"\n/>\n<img
width=\"1634\" alt=\"Screenshot 2025-03-24 at 10 36
52\"\nsrc=\"https://github.com/user-attachments/assets/d410bcc1-c075-4b5a-bcb7-11f97c64ffb9\"\n/>\n<img
width=\"825\" alt=\"Screenshot 2025-03-24 at 10 37
00\"\nsrc=\"https://github.com/user-attachments/assets/8a9e7567-5dbd-4238-8f8b-297b78a4dcac\"\n/>\n\n\n\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] Any text
added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [ ] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] The PR description includes the
appropriate Release Notes section,\nand the correct `release_note:*`
label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"01a4ff72e73c1d31b0aeed76f3a9ec4b5393deb8"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

---------

Co-authored-by: Kathleen DeRusso <kathleen.derusso@elastic.co>
Co-authored-by: Samiul Monir <samiul.monir@elastic.co>
This commit is contained in:
Efe Gürkan YALAMAN 2025-03-28 01:42:15 +01:00 committed by GitHub
parent a002e9b3c9
commit 3af1098ba3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 438 additions and 58 deletions

View file

@ -138,6 +138,7 @@ export const applicationUsageSchema = {
enterpriseSearchContent: commonSchema,
searchInferenceEndpoints: commonSchema,
searchPlayground: commonSchema,
searchSynonyms: commonSchema,
enterpriseSearchAnalytics: commonSchema,
enterpriseSearchApplications: commonSchema,
enterpriseSearchAISearch: commonSchema,

View file

@ -2360,6 +2360,137 @@
}
}
},
"searchSynonyms": {
"properties": {
"appId": {
"type": "keyword",
"_meta": {
"description": "The application being tracked"
}
},
"viewId": {
"type": "keyword",
"_meta": {
"description": "Always `main`"
}
},
"clicks_total": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application since we started counting them"
}
},
"clicks_7_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application over the last 7 days"
}
},
"clicks_30_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application over the last 30 days"
}
},
"clicks_90_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application over the last 90 days"
}
},
"minutes_on_screen_total": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen since we started counting them."
}
},
"minutes_on_screen_7_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen over the last 7 days"
}
},
"minutes_on_screen_30_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen over the last 30 days"
}
},
"minutes_on_screen_90_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen over the last 90 days"
}
},
"views": {
"type": "array",
"items": {
"properties": {
"appId": {
"type": "keyword",
"_meta": {
"description": "The application being tracked"
}
},
"viewId": {
"type": "keyword",
"_meta": {
"description": "The application view being tracked"
}
},
"clicks_total": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application sub view since we started counting them"
}
},
"clicks_7_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the active application sub view over the last 7 days"
}
},
"clicks_30_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the active application sub view over the last 30 days"
}
},
"clicks_90_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the active application sub view over the last 90 days"
}
},
"minutes_on_screen_total": {
"type": "float",
"_meta": {
"description": "Minutes the application sub view is active and on-screen since we started counting them."
}
},
"minutes_on_screen_7_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen active application sub view over the last 7 days"
}
},
"minutes_on_screen_30_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen active application sub view over the last 30 days"
}
},
"minutes_on_screen_90_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen active application sub view over the last 90 days"
}
}
}
}
}
}
},
"enterpriseSearchAnalytics": {
"properties": {
"appId": {

View file

@ -17,6 +17,7 @@
],
"optionalPlugins": [
"console",
"usageCollection",
"searchNavigation",
],
"requiredBundles": [

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export enum AnalyticsEvents {
new_set_created = 'synonyms-new-set-create-action',
new_rule_created = 'synonyms-new-rule-create-action',
set_deleted = 'synonyms-set-delete-action',
rule_deleted = 'synonyms-rule-delete-action',
rule_updated = 'synonyms-rule-update-action',
}

View file

@ -36,3 +36,40 @@ PUT my-index
}
}
}`;
export const getExistingIndexExampleCode = (rulesetId: string) => `
POST my-index/_close
PUT my-index/_settings
{
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "whitespace",
"filter": [
"synonyms_filter"
]
}
},
"filter": {
"synonyms_filter": {
"type": "synonym",
"synonyms_set": "${rulesetId}",
"updateable": true
}
}
}
}
PUT my-index/_mapping
{
"properties": {
"title": {
"type": "text",
"search_analyzer": "my_analyzer"
}
}
}
POST my-index/_open
`;

View file

@ -20,8 +20,8 @@ export const ConnectToApiButton: React.FC<ConnectToApiButtonProps> = ({ onClick
iconType="endpoint"
onClick={onClick}
>
{i18n.translate('xpack.searchSynonyms.synonymsSetDetail.connectToApiButton', {
defaultMessage: 'Connect to API',
{i18n.translate('xpack.searchSynonyms.synonymsSetDetail.assignToIndexButton', {
defaultMessage: 'Assign to index',
})}
</EuiButton>
);

View file

@ -6,6 +6,7 @@
*/
import {
EuiAccordion,
EuiButton,
EuiCodeBlock,
EuiFlexGroup,
@ -23,7 +24,7 @@ import {
import { i18n } from '@kbn/i18n';
import React from 'react';
import { docLinks } from '../../../common/doc_links';
import { getExampleCode } from './code_examples';
import { getExampleCode, getExistingIndexExampleCode } from './code_examples';
interface ConnectToApiFlyoutProps {
onClose: () => void;
@ -78,11 +79,50 @@ export const ConnectToApiFlyout: React.FC<ConnectToApiFlyoutProps> = ({ onClose,
</p>
</EuiText>
<EuiSpacer />
<EuiThemeProvider colorMode="dark">
<EuiCodeBlock language="json" isCopyable fontSize="m">
{getExampleCode(rulesetId)}
</EuiCodeBlock>
</EuiThemeProvider>
<EuiAccordion
id="connectToIndexNewIndexAccordion"
buttonContent={
<EuiTitle size="xs">
<h3>
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.exampleButton.newIndex', {
defaultMessage: 'Assigning to a new index',
})}
</h3>
</EuiTitle>
}
initialIsOpen
>
<EuiSpacer size="m" />
<EuiThemeProvider colorMode="dark">
<EuiCodeBlock language="json" isCopyable fontSize="m">
{getExampleCode(rulesetId)}
</EuiCodeBlock>
</EuiThemeProvider>
</EuiAccordion>
<EuiSpacer size="l" />
<EuiAccordion
id="connectToIndexExistingIndexAccordion"
buttonContent={
<EuiTitle size="xs">
<h3>
{i18n.translate(
'xpack.searchSynonyms.ConnectToApiFlyout.exampleButton.existingIndex',
{
defaultMessage: 'Assigning to an existing index',
}
)}
</h3>
</EuiTitle>
}
initialIsOpen
>
<EuiSpacer size="m" />
<EuiThemeProvider colorMode="dark">
<EuiCodeBlock language="json" isCopyable fontSize="m">
{getExistingIndexExampleCode(rulesetId)}
</EuiCodeBlock>
</EuiThemeProvider>
</EuiAccordion>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="flexEnd">

View file

@ -56,7 +56,7 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
<p>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.subtitle"
defaultMessage="Improve search relevance by matching terms that express the same concept."
defaultMessage="Create and manage Elasticsearch synonym sets and rules, which expand search results by matching different terms that express the same concept."
/>
</p>
</EuiText>
@ -90,8 +90,8 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
<EuiTitle size="xxs">
<h5>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.improveSearchRelevance.title"
defaultMessage="Expand search coverage"
id="xpack.searchSynonyms.emptyPrompt.instantlyAvailable.title"
defaultMessage="Instantly available changes"
/>
</h5>
</EuiTitle>
@ -102,8 +102,40 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.improveSearchRelevance.description"
defaultMessage="Include related terms your users actually use."
id="xpack.searchSynonyms.emptyPrompt.instantlyAvailable.description"
defaultMessage="Updates automatically reload the associated analyzers."
/>
</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup responsive={false} gutterSize="xs" direction="column">
<EuiFlexItem grow={false}>
<EuiFlexGroup responsive={false} gutterSize="s">
<EuiFlexItem grow={false}>
<EuiIcon type="check" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h5>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.increaseSearchScope.title"
defaultMessage="Increase search scope"
/>
</h5>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.increaseSearchScope.description"
defaultMessage="Include related terms your users commonly use."
/>
</p>
</EuiText>
@ -123,7 +155,7 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
<h5>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.domainSpecific.title"
defaultMessage="Match domain-specific terms"
defaultMessage="Domain-specific terms"
/>
</h5>
</EuiTitle>
@ -135,39 +167,7 @@ export const EmptyPrompt: React.FC<EmptyPromptProps> = ({ getStartedAction }) =>
<p>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.domainSpecific.description"
defaultMessage="Connect industry terms with common search phrases."
/>
</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup responsive={false} gutterSize="xs" direction="column">
<EuiFlexItem grow={false}>
<EuiFlexGroup responsive={false} gutterSize="s">
<EuiFlexItem grow={false}>
<EuiIcon type="check" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h5>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.improvePerformance.title"
defaultMessage="Optimize performance"
/>
</h5>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.searchSynonyms.emptyPrompt.improvedPerformance.description"
defaultMessage="Uses the built-in synonyms API for improved performance and flexibility."
defaultMessage="Adds specialized vocabulary for successful searches."
/>
</p>
</EuiText>

View file

@ -17,6 +17,7 @@ import {
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react';
import { docLinks } from '../../../common/doc_links';
import { useKibana } from '../../hooks/use_kibana';
import { SynonymSets } from '../synonym_sets/synonym_sets';
@ -92,7 +93,14 @@ export const SearchSynonymsOverview = () => {
</EuiText>
</KibanaPageTemplate.Header>
)}
<KibanaPageTemplate.Section restrictWidth>
<KibanaPageTemplate.Section
restrictWidth
contentProps={{
css: css({
height: '100%',
}),
}}
>
{isCreateModalVisible && (
<CreateSynonymsSetModal
onClose={() => {
@ -109,11 +117,22 @@ export const SearchSynonymsOverview = () => {
<SynonymSets />
)}
{!isInitialLoading && synonymsData && synonymsData._meta.totalItemCount === 0 && (
<EmptyPrompt
getStartedAction={() => {
setIsCreateModalVisible(true);
}}
/>
<EuiFlexGroup
justifyContent="center"
alignItems="center"
direction="column"
css={css({
height: '75%',
})}
>
<EuiFlexItem>
<EmptyPrompt
getStartedAction={() => {
setIsCreateModalVisible(true);
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
)}
</KibanaPageTemplate.Section>
{embeddableConsole}

View file

@ -26,6 +26,8 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { formatSynonymsSetName } from '../../utils/synonyms_utils';
import { usePutSynonymsSet } from '../../hooks/use_put_synonyms_set';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';
interface CreateSynonymsSetModalProps {
onClose: () => void;
@ -47,6 +49,7 @@ export const CreateSynonymsSetModal = ({ onClose }: CreateSynonymsSetModalProps)
setConflictError(true);
}
);
const usageTracker = useUsageTracker();
return (
<EuiModal onClose={onClose}>
<EuiModalHeader>
@ -64,6 +67,7 @@ export const CreateSynonymsSetModal = ({ onClose }: CreateSynonymsSetModalProps)
component="form"
onSubmit={(e) => {
e.preventDefault();
usageTracker?.click(AnalyticsEvents.new_set_created);
createSynonymsSet({ synonymsSetId: name, forceWrite });
}}
>

View file

@ -33,6 +33,8 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { synonymsOptionToString } from '../../utils/synonyms_utils';
import { usePutSynonymsRule } from '../../hooks/use_put_synonyms_rule';
import { useSynonymRuleFlyoutState } from './use_flyout_state';
import { AnalyticsEvents } from '../../analytics/constants';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
interface SynonymRuleFlyoutProps {
onClose: () => void;
@ -52,6 +54,7 @@ export const SynonymRuleFlyout: React.FC<SynonymRuleFlyoutProps> = ({
const { euiTheme } = useEuiTheme();
const [backendError, setBackendError] = React.useState<string | null>(null);
const usageTracker = useUsageTracker();
const { mutate: putSynonymsRule } = usePutSynonymsRule(
() => onClose(),
(error) => {
@ -282,6 +285,7 @@ export const SynonymRuleFlyout: React.FC<SynonymRuleFlyoutProps> = ({
error={mapToTermErrors || null}
>
<EuiFieldText
prepend={'=>'}
data-test-subj="searchSynonymsSynonymsRuleFlyoutMapToTermsInput"
fullWidth
value={mapToTerms}
@ -332,6 +336,11 @@ export const SynonymRuleFlyout: React.FC<SynonymRuleFlyoutProps> = ({
if (!synonymsRule.id) {
return;
}
if (flyoutMode === 'create') {
usageTracker?.click(AnalyticsEvents.new_rule_created);
} else {
usageTracker?.click(AnalyticsEvents.rule_updated);
}
putSynonymsRule({
synonymsSetId,
ruleId: synonymsRule.id,

View file

@ -9,6 +9,8 @@ import React, { useState } from 'react';
import { EuiConfirmModal } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useDeleteSynonymRule } from '../../hooks/use_delete_synonym_rule';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { AnalyticsEvents } from '../../analytics/constants';
export interface DeleteSynonymRuleModalProps {
synonymsSetId: string;
@ -34,9 +36,11 @@ export const DeleteSynonymRuleModal = ({
};
const { mutate: deleteEndpoint } = useDeleteSynonymRule(onSuccess, onError);
const usageTracker = useUsageTracker();
const deleteOperation = () => {
setIsLoading(true);
usageTracker?.click(AnalyticsEvents.rule_deleted);
deleteEndpoint({ synonymsSetId, ruleId });
};

View file

@ -45,7 +45,7 @@ export const SynonymsSetEmptyRulesCards: React.FC<SynonymsSetEmptyRulesCardsProp
description={i18n.translate(
'xpack.searchSynonyms.synonymsSetEmptyRulesCards.equivalent.description',
{
defaultMessage: 'Defines groups of words that are the same.',
defaultMessage: 'Interchangeable words that will match each other.',
}
)}
footer={
@ -122,7 +122,7 @@ export const SynonymsSetEmptyRulesCards: React.FC<SynonymsSetEmptyRulesCardsProp
description={i18n.translate(
'xpack.searchSynonyms.synonymsSetEmptyRulesCards.explicit.description',
{
defaultMessage: 'Matches a group of words to another word.',
defaultMessage: 'Words that expand to include the terms on the right.',
}
)}
footer={

View file

@ -0,0 +1,74 @@
/*
* 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 { renderHook } from '@testing-library/react';
import { useKibana } from './use_kibana';
import { useUsageTracker } from './use_usage_tracker';
jest.mock('./use_kibana', () => ({
useKibana: jest.fn(),
}));
describe('useUsageTracker', () => {
let reportUiCounter: jest.Mock;
beforeEach(() => {
reportUiCounter = jest.fn();
(useKibana as jest.Mock).mockReturnValue({
services: { usageCollection: { reportUiCounter } },
});
});
afterEach(() => {
jest.clearAllMocks();
});
it('returns bound functions for tracking usage', () => {
const { result } = renderHook(() => useUsageTracker());
expect(typeof result.current?.click).toBe('function');
expect(typeof result.current?.count).toBe('function');
expect(typeof result.current?.load).toBe('function');
});
it('calls reportUiCounter with correct arguments for click', () => {
const { result } = renderHook(() => useUsageTracker());
result.current?.click('button_click');
expect(reportUiCounter).toHaveBeenCalledWith('search_synonyms', 'click', 'button_click');
});
it('calls reportUiCounter with correct arguments for count', () => {
const { result } = renderHook(() => useUsageTracker());
result.current?.count('item_count');
expect(reportUiCounter).toHaveBeenCalledWith('search_synonyms', 'count', 'item_count');
});
it('calls reportUiCounter with correct arguments for load', () => {
const { result } = renderHook(() => useUsageTracker());
result.current?.load('page_loaded');
expect(reportUiCounter).toHaveBeenCalledWith('search_synonyms', 'loaded', 'page_loaded');
});
it('does not reportUiCounter if usageCollection is not loaded properly', () => {
reportUiCounter = jest.fn();
(useKibana as jest.Mock).mockReturnValue({
services: { usageCollection: undefined },
});
const { result } = renderHook(() => useUsageTracker());
result.current?.load('page_loaded');
expect(reportUiCounter).toHaveBeenCalledTimes(0);
});
});

View file

@ -0,0 +1,38 @@
/*
* 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 { METRIC_TYPE } from '@kbn/analytics';
import { useMemo } from 'react';
import { useKibana } from './use_kibana';
const APP_TRACKER_NAME = 'search_synonyms';
export const useUsageTracker = () => {
const { usageCollection } = useKibana().services;
return useMemo(() => {
if (usageCollection) {
return {
click: usageCollection.reportUiCounter.bind(
usageCollection,
APP_TRACKER_NAME,
METRIC_TYPE.CLICK
),
count: usageCollection.reportUiCounter.bind(
usageCollection,
APP_TRACKER_NAME,
METRIC_TYPE.COUNT
),
load: usageCollection.reportUiCounter.bind(
usageCollection,
APP_TRACKER_NAME,
METRIC_TYPE.LOADED
),
};
}
}, [usageCollection]);
};

View file

@ -26,7 +26,7 @@ export class SearchSynonymsPlugin
core: CoreSetup<AppPluginStartDependencies, SearchSynonymsPluginStart>,
_: AppPluginSetupDependencies
): SearchSynonymsPluginSetup {
if (!core.settings.client.get<boolean>(SYNONYMS_UI_FLAG, false)) {
if (!core.settings.client.get<boolean>(SYNONYMS_UI_FLAG, true)) {
return {};
}
core.application.register({

View file

@ -5,14 +5,16 @@
* 2.0.
*/
import { SearchNavigationPluginStart } from '@kbn/search-navigation/public';
import { AppMountParameters, CoreStart } from '@kbn/core/public';
import type { SearchNavigationPluginStart } from '@kbn/search-navigation/public';
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
import type { ConsolePluginStart } from '@kbn/console-plugin/public';
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
export * from '../common/types';
export interface AppPluginStartDependencies {
history: AppMountParameters['history'];
console?: ConsolePluginStart;
usageCollection?: UsageCollectionStart;
searchNavigation?: SearchNavigationPluginStart;
}

View file

@ -25,6 +25,8 @@
"@kbn/core-http-server",
"@kbn/kibana-utils-plugin",
"@kbn/logging",
"@kbn/analytics",
"@kbn/usage-collection-plugin",
],
"exclude": [
"target/**/*",

View file

@ -49,6 +49,7 @@ export default function searchSolutionNavigation({
{ id: 'BehavioralAnalytics', label: 'Behavioral Analytics' },
{ id: 'Relevance', label: 'Relevance' },
{ id: 'InferenceEndpoints', label: 'Inference Endpoints' },
{ id: 'Synonyms', label: 'Synonyms' },
{ id: 'GettingStarted', label: 'Getting started' },
{ id: 'Elasticsearch', label: 'Elasticsearch' },
{ id: 'VectorSearch', label: 'Vector Search' },

View file

@ -294,6 +294,7 @@ export default function searchSolutionNavigation({
'enterpriseSearchContent:webCrawlers',
'build',
'searchPlayground',
'searchSynonyms:synonyms',
'enterpriseSearchApplications:searchApplications',
'enterpriseSearchAnalytics',
'relevance',

View file

@ -264,6 +264,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
await solutionNavigation.sidenav.expectLinkExists({ text: 'Playground' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Relevance' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Inference Endpoints' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Synonyms' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Analyze' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Discover' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Dashboards' });
@ -285,6 +286,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
'build',
'dev_tools',
'searchPlayground',
'searchSynonyms',
'relevance',
'searchInferenceEndpoints',
'analyze',