[Synonyms UI] Fix rendering issues and adds a code example (#210229)

## Summary

Improved rendering when long lists are added with explicit rule.
Added code example flyout.
<img width="1075" alt="Screenshot 2025-02-07 at 18 09 18"
src="https://github.com/user-attachments/assets/95020f5b-8162-4cb7-bf7a-11439ff5b2d0"
/>
<img width="1049" alt="Screenshot 2025-02-07 at 18 09 26"
src="https://github.com/user-attachments/assets/5912e930-1356-4919-b637-92ca4009bc30"
/>



### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Efe Gürkan YALAMAN 2025-02-10 12:27:58 +01:00 committed by GitHub
parent 0d5cecc2af
commit e326c7759a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 210 additions and 9 deletions

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.
*/
export const getExampleCode = (rulesetId: string) => `
PUT my-index
{
"mappings": {
"properties": {
"title": {
"type": "text",
"search_analyzer": "my_analyzer"
}
}
},
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "whitespace",
"filter": [
"synonyms_filter"
]
}
},
"filter": {
"synonyms_filter": {
"type": "synonym",
"synonyms_set": "${rulesetId}",
"updateable": true
}
}
}
}
}`;

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiButton } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
interface ConnectToApiButtonProps {
onClick: () => void;
}
export const ConnectToApiButton: React.FC<ConnectToApiButtonProps> = ({ onClick }) => {
return (
<EuiButton
data-test-subj="searchSynonymsSynonymsSetDetailConnectToApiButton"
color="text"
iconType="endpoint"
onClick={onClick}
>
{i18n.translate('xpack.searchSynonyms.synonymsSetDetail.connectToApiButton', {
defaultMessage: 'Connect to API',
})}
</EuiButton>
);
};

View file

@ -0,0 +1,104 @@
/*
* 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 {
EuiButton,
EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiLink,
EuiSpacer,
EuiText,
EuiThemeProvider,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { docLinks } from '../../../common/doc_links';
import { getExampleCode } from './code_examples';
interface ConnectToApiFlyoutProps {
onClose: () => void;
rulesetId: string;
}
export const ConnectToApiFlyout: React.FC<ConnectToApiFlyoutProps> = ({ onClose, rulesetId }) => {
return (
<EuiFlyout onClose={onClose} size="m">
<EuiFlyoutHeader hasBorder>
<EuiFlexGroup justifyContent="spaceBetween" direction="column">
<EuiFlexItem grow={false}>
<EuiTitle size="m">
<h2>
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.title', {
defaultMessage: 'Connect with the API',
})}
</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s" color="subdued">
<p>
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.description', {
defaultMessage: 'You can access and manage this synonym set from the API.',
})}
</p>
</EuiText>
<EuiSpacer size="xs" />
<EuiLink
data-test-subj="searchSynonymsConnectToApiFlyoutViewFullApiReferenceLink"
href={docLinks.synonymsApi}
external
>
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.viewFullApiReference', {
defaultMessage: 'View full API reference',
})}
</EuiLink>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiText size="s">
<p>
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.description', {
defaultMessage: `You can specify the analyzer that contains your synonyms set as a search time analyzer.`,
})}
<EuiSpacer size="s" />
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.description.example', {
defaultMessage: `The following example adds my_analyzer as a search analyzer to the title field in an index mapping`,
})}
</p>
</EuiText>
<EuiSpacer />
<EuiThemeProvider colorMode="dark">
<EuiCodeBlock language="json" isCopyable fontSize="m">
{getExampleCode(rulesetId)}
</EuiCodeBlock>
</EuiThemeProvider>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton
fill
data-test-subj="searchSynonymsConnectToApiFlyoutButton"
onClick={onClose}
>
{i18n.translate('xpack.searchSynonyms.ConnectToApiFlyout.close', {
defaultMessage: 'Close',
})}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>
);
};

View file

@ -10,6 +10,8 @@ import React, { useMemo } from 'react';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import { useKibana } from '../../hooks/use_kibana';
import { SynonymsSetRuleTable } from './synonyms_set_rule_table';
import { ConnectToApiButton } from '../connect_to_api/connect_to_api_button';
import { ConnectToApiFlyout } from '../connect_to_api/connect_to_api_flyout';
export const SynonymsSetDetail = () => {
const { synonymsSetId = '' } = useParams<{
@ -23,6 +25,7 @@ export const SynonymsSetDetail = () => {
() => (consolePlugin?.EmbeddableConsole ? <consolePlugin.EmbeddableConsole /> : null),
[consolePlugin]
);
const [isApiConnectModalVisible, setIsApiConnectModalVisible] = React.useState(false);
return (
<KibanaPageTemplate
@ -33,9 +36,28 @@ export const SynonymsSetDetail = () => {
solutionNav={searchNavigation?.useClassicNavigation(history)}
color="primary"
>
<KibanaPageTemplate.Header pageTitle={synonymsSetId} restrictWidth color="primary" />
<KibanaPageTemplate.Header
pageTitle={synonymsSetId}
restrictWidth
color="primary"
rightSideItems={[
<ConnectToApiButton
onClick={() => {
setIsApiConnectModalVisible(true);
}}
/>,
]}
/>
<KibanaPageTemplate.Section restrictWidth>
{synonymsSetId && <SynonymsSetRuleTable synonymsSetId={synonymsSetId} />}
{isApiConnectModalVisible && (
<ConnectToApiFlyout
rulesetId={synonymsSetId}
onClose={() => {
setIsApiConnectModalVisible(false);
}}
/>
)}
</KibanaPageTemplate.Section>
{embeddableConsole}
</KibanaPageTemplate>

View file

@ -72,7 +72,7 @@ export const SynonymsRuleFlyout: React.FC<SynonymsRuleFlyoutProps> = ({
synonymsOptionToString({ fromTerms: selectedFromTerms, toTerms: selectedToTerms, isExplicit });
return (
<EuiFlyout onClose={onClose}>
<EuiFlyout onClose={onClose} size="s">
<EuiFlyoutHeader hasBorder aria-labelledby={flyoutHeadingId}>
{flyoutMode === 'edit' ? (
<EuiText>
@ -103,6 +103,7 @@ export const SynonymsRuleFlyout: React.FC<SynonymsRuleFlyoutProps> = ({
})}
>
<EuiComboBox
fullWidth
title="Synonyms"
id="synonyms"
options={selectedFromTerms}
@ -130,6 +131,7 @@ export const SynonymsRuleFlyout: React.FC<SynonymsRuleFlyoutProps> = ({
})}
>
<EuiComboBox
fullWidth
title="Synonyms"
id="synonyms-to"
options={selectedToTerms}

View file

@ -17,6 +17,7 @@ import {
EuiPopover,
EuiPopoverTitle,
EuiText,
EuiTextTruncate,
} from '@elastic/eui';
import { SynonymsSynonymRule } from '@elastic/elasticsearch/lib/api/types';
import { i18n } from '@kbn/i18n';
@ -97,14 +98,20 @@ export const SynonymsSetRuleTable = ({ synonymsSetId = '' }: { synonymsSetId: st
</EuiFlexItem>
{isExplicit ? (
<>
<EuiFlexItem data-test-subj="synonyms-set-item-explicit-from">
<EuiCode>{explicitFrom}</EuiCode>
<EuiFlexItem data-test-subj="synonyms-set-item-explicit-from" grow={7}>
<EuiCode>
<EuiTextTruncate text={explicitFrom} />
</EuiCode>
</EuiFlexItem>
<EuiText>
<b>{'=>'}</b>
</EuiText>
<EuiFlexItem grow={false} data-test-subj="synonyms-set-item-explicit-to">
<EuiCode>{explicitTo}</EuiCode>
<EuiFlexItem grow={false}>
<EuiText>
<b>{'=>'}</b>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={1} data-test-subj="synonyms-set-item-explicit-to">
<EuiCode>
<EuiTextTruncate text={explicitTo} />
</EuiCode>
</EuiFlexItem>
</>
) : (