Porting fixes 1 (#88477)

* Remove Manage button from Source overview page

* Replace empty select option with "Leave unassigned"

* Replace content source key with id

* Update Google icons

* Replace anchor with EuiLink

* Add Folders as one of the synced items for Box

* Add DLP feature UI to Jira and Confluence cloud pages

* Fix the "Fix" link path

Also updated TS types to match ent-search

* Fix copy and button color on "Content source is disabled" callout

* Remove incorrect copy from Private sources empty state

* Move constants from logic file to a separate file, rename a constant

* Fix i18n path to not include file name

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Vadim Yakhin 2021-01-15 18:04:45 -04:00 committed by GitHub
parent f5ec1dc352
commit fbb8238f57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 79 additions and 71 deletions

View file

@ -1 +1 @@
<svg height="100" viewBox="0 0 100 100" width="100" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" transform="translate(21 29)"><path d="m55.074 0c2.706 0 4.92 2.22169863 4.92 4.93764384v1.43150684l-6.828 4.90027402-23.25 16.0883287-23.25-16.2516712v32.5015342h-1.752c-2.7 0-4.914-2.2223013-4.914-4.9376438v-33.73112328c0-2.71594521 2.214-4.93764384 4.914-4.93764384l25.002 18.61923292 25.158-18.61923292z" fill="#e75a4d"/><path d="m6.666 11.106v32.502h46.5v-32.339l-23.25 16.089z" fill="#e7e4d7"/><path d="m6.666 43.608 23.25-16.25-.108-.076-23.142 15.968z" fill="#b8b7ae"/><path d="m53.166 11.269.012 32.339-23.262-16.25z" fill="#b7b6ad"/><path d="m59.994 6.36915068.006 32.30443832c-.12 3.5911233-1.668 4.872548-6.822 4.932822l-.012-32.3387946 6.828-4.90027393z" fill="#b2392f"/><path d="m4.914 0 25.002 18.619 25.158-18.619z" fill="#f7f5ed"/></g></svg>
<svg width="100" height="100" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M24.09 72.01h9.546V48.83L20 38.601V67.92a4.09 4.09 0 004.09 4.09z" fill="#4285F4"/><path d="M66.364 72.01h9.545A4.09 4.09 0 0080 67.92V38.602L66.364 48.829v23.182z" fill="#34A853"/><path d="M66.364 31.102v17.727L80 38.602v-5.455c0-5.055-5.772-7.943-9.818-4.909l-3.818 2.864z" fill="#FBBC04"/><path d="M33.636 48.83V31.101L50 43.374l16.364-12.272v17.727L50 61.102 33.636 48.829z" fill="#EA4335"/><path d="M20 33.147v5.455l13.636 10.227V31.102l-3.818-2.864C25.772 25.204 20 28.092 20 33.148z" fill="#C5221F"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(20 27)" d="M0 0h60v45.011H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 879 B

After

Width:  |  Height:  |  Size: 745 B

Before After
Before After

View file

@ -1 +1 @@
<svg height="52" viewBox="0 0 52 52" width="52" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="26" cy="26" fill="#f9fafb" r="26"/><g transform="translate(8 10)"><path d="m5.98703634 31.1142993 5.98622706-10.3714331h23.9467966l-5.9867666 10.3714331z" fill="#3777e3"/><path d="m23.9470663 20.7428662h11.9729937l-11.9729937-20.7428662h-11.9738029z" fill="#ffcf63"/><path d="m0 20.7428662 5.98703634 10.3714331 11.97299366-20.7428662-5.9867666-10.3714331z" fill="#11a861"/></g></g></svg>
<svg width="100" height="100" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M24.536 68.945l2.646 4.57c.55.963 1.34 1.719 2.268 2.269l9.45-16.358H20c0 1.065.275 2.13.825 3.093l3.711 6.426z" fill="#0066DA"/><path d="M50 40.182l-9.45-16.357c-.928.55-1.718 1.306-2.268 2.268l-17.457 30.24A6.227 6.227 0 0020 59.426h18.9L50 40.182z" fill="#00AC47"/><path d="M70.55 75.784c.928-.55 1.718-1.306 2.268-2.269l1.1-1.89 5.257-9.106c.55-.962.825-2.028.825-3.093H61.098l4.022 7.904 5.43 8.454z" fill="#EA4335"/><path d="M50 40.182l9.45-16.357A6.042 6.042 0 0056.357 23H43.643c-1.1 0-2.165.31-3.093.825L50 40.182z" fill="#00832D"/><path d="M61.1 59.426H38.9l-9.45 16.358a6.04 6.04 0 003.093.824h34.914c1.1 0 2.165-.309 3.093-.825L61.1 59.427z" fill="#2684FC"/><path d="M70.447 41.213l-8.729-15.12c-.55-.962-1.34-1.718-2.268-2.268L50 40.182l11.1 19.244h18.866c0-1.065-.275-2.13-.825-3.093l-8.694-15.12z" fill="#FFBA00"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(20 23)" d="M0 0h60v53.608H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 518 B

After

Width:  |  Height:  |  Size: 1 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg fill="none" height="100" viewBox="0 0 100 100" width="100" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill-rule="evenodd"><path d="m91.79 14c4.51 0 8.2 3.7028 8.2 8.2294v2.3858l-11.38 8.1672-38.75 26.8138-38.75-27.0861v54.1692h-2.92c-4.5 0-8.19-3.7038-8.19-8.2294v-56.2185c0-4.5266 3.69-8.2294 8.19-8.2294l41.67 31.032 41.93-31.032z" fill="#e75a4d"/><path d="m11.11 32.51v54.17h77.4999v-53.8983l-38.7499 26.815z" fill="#e7e4d7"/><path d="m11.11 86.68 38.75-27.0834-.18-.1266-38.57 26.6133z" fill="#b8b7ae"/><path d="m88.6099 32.7817.02 53.8983-38.77-27.0833z" fill="#b7b6ad"/><path d="m99.99 24.6152.01 53.8407c-.2 5.9852-2.78 8.1209-11.37 8.2214l-.02-53.898 11.38-8.1671z" fill="#b2392f"/><path d="m8.19006 14 41.66994 31.0316 41.93-31.0316z" fill="#f7f5ed"/></g></svg>
<svg width="100" height="100" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M6.818 87.517h15.91V48.881L0 31.835V80.7a6.816 6.816 0 006.818 6.818z" fill="#4285F4"/><path d="M77.273 87.517h15.909A6.816 6.816 0 00100 80.7V31.835L77.273 48.881v38.636z" fill="#34A853"/><path d="M77.273 19.335v29.546L100 31.835v-9.09c0-8.427-9.62-13.24-16.364-8.183l-6.363 4.773z" fill="#FBBC04"/><path d="M22.727 48.88V19.336L50 39.79l27.273-20.455v29.546L50 69.335 22.727 48.881z" fill="#EA4335"/><path d="M0 22.744v9.091l22.727 17.046V19.335l-6.363-4.773C9.619 9.506 0 14.319 0 22.745z" fill="#C5221F"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 12.499)" d="M0 0h100v75.018H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 751 B

Before After
Before After

View file

@ -1 +1 @@
<svg fill="none" height="100" viewBox="0 0 100 100" width="100" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill-rule="evenodd"><path d="m16.668 93.6196 16.6653-28.8735h66.6666l-16.6668 28.8735z" fill="#3777e3"/><path d="m66.6678 64.747h33.3322l-33.3322-57.747h-33.3344z" fill="#ffcf63"/><path d="m0 64.747 16.6676 28.8735 33.3322-57.747-16.6669-28.8735z" fill="#11a861"/></g></svg>
<svg width="100" height="100" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><g clip-path="url(#clip1)"><path d="M6.913 82.125l4.441 7.67c.923 1.615 2.25 2.884 3.807 3.807L31.02 66.15H-.7c0 1.788.461 3.576 1.384 5.19l6.23 10.786z" fill="#0066DA"/><path d="M49.65 33.851L33.79 6.398c-1.558.923-2.884 2.192-3.807 3.806L.684 60.959A10.45 10.45 0 00-.7 66.148h31.721L49.65 33.852z" fill="#00AC47"/><path d="M84.14 93.602c1.557-.923 2.883-2.192 3.806-3.806l1.846-3.173 8.824-15.283A10.45 10.45 0 00100 66.149H68.277l6.75 13.265 9.112 14.188z" fill="#EA4335"/><path d="M49.65 33.851L65.51 6.398c-1.557-.923-3.345-1.384-5.19-1.384H38.98c-1.845 0-3.633.519-5.19 1.384L49.65 33.85z" fill="#00832D"/><path d="M68.279 66.149H31.02l-15.86 27.453c1.557.923 3.345 1.384 5.19 1.384H78.95c1.845 0 3.633-.519 5.19-1.384L68.28 66.15z" fill="#2684FC"/><path d="M83.966 35.581L69.317 10.204c-.923-1.614-2.25-2.883-3.806-3.806L49.65 33.85 68.279 66.15h31.663a10.45 10.45 0 00-1.384-5.19L83.966 35.58z" fill="#FFBA00"/></g></g><defs><clipPath id="clip0"><path fill="#fff" d="M0 0h100v100H0z"/></clipPath><clipPath id="clip1"><path fill="#fff" transform="translate(-.7 5.014)" d="M0 0h100.7v89.972H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

View file

@ -26,7 +26,12 @@ import {
import { EuiLinkTo } from '../../../../shared/react_router_helpers';
import { SOURCE_STATUSES as statuses } from '../../../constants';
import { ContentSourceDetails } from '../../../types';
import { ADD_SOURCE_PATH, SOURCE_DETAILS_PATH, getContentSourcePath } from '../../../routes';
import {
ADD_SOURCE_PATH,
SOURCE_DETAILS_PATH,
getContentSourcePath,
getSourcesPath,
} from '../../../routes';
import { SourceIcon } from '../source_icon';
@ -77,7 +82,12 @@ export const SourceRow: React.FC<SourceRowProps> = ({
const imageClass = classNames('source-row__icon', { 'source-row__icon--loading': isIndexing });
const fixLink = (
<EuiLinkTo to={`${ADD_SOURCE_PATH}/${_kebabCase(serviceType)}/re-authenticate?sourceId=${id}`}>
<EuiLinkTo
to={getSourcesPath(
`${ADD_SOURCE_PATH}/${_kebabCase(serviceType)}/re-authenticate?sourceId=${id}`,
isOrganization
)}
>
Fix
</EuiLinkTo>
);

View file

@ -136,6 +136,9 @@ export const SOURCE_NAMES = {
};
export const SOURCE_OBJ_TYPES = {
FOLDERS: i18n.translate('xpack.enterpriseSearch.workplaceSearch.sources.objTypes.folders', {
defaultMessage: 'Folders',
}),
PAGES: i18n.translate('xpack.enterpriseSearch.workplaceSearch.sources.objTypes.pages', {
defaultMessage: 'Pages',
}),

View file

@ -124,7 +124,7 @@ export const getContentSourcePath = (
export const getGroupPath = (groupId: string): string => generatePath(GROUP_PATH, { groupId });
export const getGroupSourcePrioritizationPath = (groupId: string): string =>
`${GROUPS_PATH}/${groupId}/source_prioritization`;
export const getSourcesPath = (path: string, isOrganization: boolean): string =>
export const getSourcesPath = (path: string, isOrganization?: boolean): string =>
isOrganization ? path : `${PERSONAL_PATH}${path}`;
export const getReindexJobRoute = (
sourceId: string,

View file

@ -130,7 +130,6 @@ export interface ContentSourceFullData extends ContentSourceDetails {
groups: Group[];
custom: boolean;
accessToken: string;
key: string;
urlField: string;
titleField: string;
licenseSupportsPermissions: boolean;
@ -177,7 +176,6 @@ export enum FeatureIds {
export interface CustomSource {
accessToken: string;
key: string;
name: string;
id: string;
}

View file

@ -299,10 +299,10 @@ export const SAVE_CUSTOM_ACCESS_TOKEN_LABEL = i18n.translate(
}
);
export const SAVE_CUSTOM_API_KEY_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSource.saveCustom.apiKey.label',
export const SAVE_CUSTOM_ID_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSource.saveCustom.id.label',
{
defaultMessage: 'Key',
defaultMessage: 'ID',
}
);

View file

@ -43,7 +43,7 @@ import {
SAVE_CUSTOM_API_KEYS_TITLE,
SAVE_CUSTOM_API_KEYS_BODY,
SAVE_CUSTOM_ACCESS_TOKEN_LABEL,
SAVE_CUSTOM_API_KEY_LABEL,
SAVE_CUSTOM_ID_LABEL,
SAVE_CUSTOM_VISUAL_WALKTHROUGH_TITLE,
SAVE_CUSTOM_STYLING_RESULTS_TITLE,
SAVE_CUSTOM_DOC_PERMISSIONS_TITLE,
@ -59,7 +59,7 @@ interface SaveCustomProps {
export const SaveCustom: React.FC<SaveCustomProps> = ({
documentationUrl,
newCustomSource: { key, id, accessToken, name },
newCustomSource: { id, accessToken, name },
isOrganization,
header,
}) => (
@ -109,17 +109,13 @@ export const SaveCustom: React.FC<SaveCustomProps> = ({
<p>{SAVE_CUSTOM_API_KEYS_BODY}</p>
</EuiText>
<EuiSpacer />
<CredentialItem label={SAVE_CUSTOM_ID_LABEL} value={id} testSubj="ContentSourceId" />
<EuiSpacer />
<CredentialItem
label={SAVE_CUSTOM_ACCESS_TOKEN_LABEL}
value={accessToken}
testSubj="AccessToken"
/>
<EuiSpacer />
<CredentialItem
label={SAVE_CUSTOM_API_KEY_LABEL}
value={key}
testSubj="ContentSourceKey"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>

View file

@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
export const LEAVE_UNASSIGNED_FIELD = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.displaySettings.leaveUnassignedField',
{
defaultMessage: 'Leave unassigned',
}
);
export const SUCCESS_MESSAGE = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.displaySettings.successMessage',
{
defaultMessage: 'Display Settings have been successfuly updated.',
}
);

View file

@ -20,10 +20,8 @@ import {
import { AppLogic } from '../../../../app_logic';
import { SourceLogic } from '../../source_logic';
const SUCCESS_MESSAGE = 'Display Settings have been successfuly updated.';
import { DetailField, SearchResultConfig, OptionValue, Result } from '../../../../types';
import { LEAVE_UNASSIGNED_FIELD, SUCCESS_MESSAGE } from './constants';
export interface DisplaySettingsResponseProps {
sourceName: string;
searchResultConfig: SearchResultConfig;
@ -271,7 +269,10 @@ export const DisplaySettingsLogic = kea<
() => [selectors.fieldOptions],
(fieldOptions) => {
const optionalFieldOptions = cloneDeep(fieldOptions);
optionalFieldOptions.unshift({ value: '', text: '' });
optionalFieldOptions.unshift({
value: LEAVE_UNASSIGNED_FIELD,
text: LEAVE_UNASSIGNED_FIELD,
});
return optionalFieldOptions;
},
],

View file

@ -21,6 +21,7 @@ import {
} from '@elastic/eui';
import { DisplaySettingsLogic } from './display_settings_logic';
import { LEAVE_UNASSIGNED_FIELD } from './constants';
import { ExampleSearchResultGroup } from './example_search_result_group';
import { ExampleStandoutResult } from './example_standout_result';
@ -104,8 +105,10 @@ export const SearchResults: React.FC = () => {
className="field-selector"
hasNoInitialSelection={true}
data-test-subj="SubtitleFieldSelect"
value={subtitleField || ''}
onChange={({ target: { value } }) => setSubtitleField(value === '' ? null : value)}
value={subtitleField || LEAVE_UNASSIGNED_FIELD}
onChange={({ target: { value } }) =>
setSubtitleField(value === LEAVE_UNASSIGNED_FIELD ? null : value)
}
/>
</EuiFormRow>
<EuiFormRow
@ -121,9 +124,9 @@ export const SearchResults: React.FC = () => {
className="field-selector"
hasNoInitialSelection={true}
data-test-subj="DescriptionFieldSelect"
value={descriptionField || ''}
value={descriptionField || LEAVE_UNASSIGNED_FIELD}
onChange={({ target: { value } }) =>
setDescriptionField(value === '' ? null : value)
setDescriptionField(value === LEAVE_UNASSIGNED_FIELD ? null : value)
}
/>
</EuiFormRow>

View file

@ -33,8 +33,6 @@ import {
DOCUMENT_PERMISSIONS_DOCS_URL,
ENT_SEARCH_LICENSE_MANAGEMENT,
EXTERNAL_IDENTITIES_DOCS_URL,
SOURCE_CONTENT_PATH,
getContentSourcePath,
getGroupPath,
} from '../../../routes';
@ -45,7 +43,7 @@ import { CredentialItem } from '../../../components/shared/credential_item';
import { ViewContentHeader } from '../../../components/shared/view_content_header';
import { LicenseBadge } from '../../../components/shared/license_badge';
import { Loading } from '../../../../shared/loading';
import { EuiButtonEmptyTo, EuiPanelTo } from '../../../../shared/react_router_helpers';
import { EuiPanelTo } from '../../../../shared/react_router_helpers';
import aclImage from '../../../assets/supports_acl.svg';
import { SourceLogic } from '../source_logic';
@ -63,7 +61,6 @@ export const Overview: React.FC = () => {
details,
custom,
accessToken,
key,
licenseSupportsPermissions,
serviceTypeSupportsPermissions,
indexPermissions,
@ -105,24 +102,9 @@ export const Overview: React.FC = () => {
return (
<div className="content-section">
<div className="section-header">
<EuiFlexGroup gutterSize="none" alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem>
<EuiTitle size="xs">
<h4>Content summary</h4>
</EuiTitle>
</EuiFlexItem>
{totalDocuments > 0 && (
<EuiFlexItem grow={false}>
<EuiButtonEmptyTo
to={getContentSourcePath(SOURCE_CONTENT_PATH, id, isOrganization)}
data-test-subj="ManageSourceContentLink"
size="s"
>
Manage
</EuiButtonEmptyTo>
</EuiFlexItem>
)}
</EuiFlexGroup>
<EuiTitle size="xs">
<h4>Content summary</h4>
</EuiTitle>
</div>
<EuiSpacer size="s" />
{!summary && <ComponentLoader text="Loading summary details..." />}
@ -388,9 +370,9 @@ export const Overview: React.FC = () => {
</h6>
</EuiText>
<EuiSpacer size="s" />
<CredentialItem label="Access Token" value={accessToken} testSubj="AccessToken" />
<CredentialItem label="ID" value={id} testSubj="ContentSourceId" />
<EuiSpacer size="s" />
<CredentialItem label="Key" value={key} testSubj="ContentSourceKey" />
<CredentialItem label="Access Token" value={accessToken} testSubj="AccessToken" />
</EuiPanel>
);

View file

@ -107,16 +107,7 @@ export const PrivateSources: React.FC = () => {
<ContentSection className="zero-state__private-sources">
<EuiPanel className="euiPanel--inset">
<EuiSpacer size="xxl" />
<EuiEmptyPrompt
iconType="lock"
title={<h2>You have no private sources</h2>}
body={
<p>
Select from the content sources below to create a private source, available only to
you
</p>
}
/>
<EuiEmptyPrompt iconType="lock" title={<h2>You have no private sources</h2>} />
<EuiSpacer size="xxl" />
</EuiPanel>
</ContentSection>

View file

@ -106,7 +106,7 @@ export const staticSourceData = [
}
),
connectStepDescription: connectStepDescription.files,
objTypes: [SOURCE_OBJ_TYPES.ALL_FILES],
objTypes: [SOURCE_OBJ_TYPES.FOLDERS, SOURCE_OBJ_TYPES.ALL_FILES],
features: {
basicOrgContext: [
FeatureIds.SyncFrequency,
@ -156,6 +156,7 @@ export const staticSourceData = [
FeatureIds.SyncedItems,
FeatureIds.GlobalAccessPermissions,
],
basicOrgContextExcludedFeatures: [FeatureIds.DocumentLevelPermissions],
platinumOrgContext: [FeatureIds.SyncFrequency, FeatureIds.SyncedItems],
platinumPrivateContext: [
FeatureIds.Private,
@ -435,6 +436,7 @@ export const staticSourceData = [
FeatureIds.SyncedItems,
FeatureIds.GlobalAccessPermissions,
],
basicOrgContextExcludedFeatures: [FeatureIds.DocumentLevelPermissions],
platinumOrgContext: [FeatureIds.SyncFrequency, FeatureIds.SyncedItems],
platinumPrivateContext: [
FeatureIds.Private,

View file

@ -84,12 +84,13 @@ export const SourceRouter: React.FC = () => {
<>
<EuiCallOut title="Content source is disabled" color="warning" iconType="alert">
<p>
Your organization&apos;s license level changed and no longer supports document-level
permissions.{' '}
Your organizations license level has changed. Your data is safe, but document-level
permissions are no longer supported and searching of this source has been disabled.
Upgrade to a Platinum license to re-enable this source.
</p>
<p>Don&apos;t worry: your data is safe. Search has been disabled.</p>
<p>Upgrade to a Platinum license to re-enable this source.</p>
<EuiButton href={ENT_SEARCH_LICENSE_MANAGEMENT}>Explore Platinum license</EuiButton>
<EuiButton color="warning" href={ENT_SEARCH_LICENSE_MANAGEMENT}>
Explore Platinum license
</EuiButton>
</EuiCallOut>
<EuiSpacer />
</>

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { EuiSpacer, EuiTitle, EuiText, EuiButton } from '@elastic/eui';
import { EuiSpacer, EuiTitle, EuiText, EuiButton, EuiLink } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
@ -30,7 +30,7 @@ export const SetupGuide: React.FC = () => {
<SetPageChrome trail={[SETUP_GUIDE_TITLE]} />
<SendTelemetry action="viewed" metric="setup_guide" />
<a href={GETTING_STARTED_LINK_URL} target="_blank" rel="noopener noreferrer">
<EuiLink href={GETTING_STARTED_LINK_URL} target="_blank">
<img
className="setupGuide__thumbnail"
src={GettingStarted}
@ -41,7 +41,7 @@ export const SetupGuide: React.FC = () => {
width="1280"
height-="720"
/>
</a>
</EuiLink>
<EuiTitle size="s">
<p>