[AppSearch] Add click count to ResultHeader component (#122981)

* Add click count to ResultHeader component

This adds click count to the header item for the suggested Adaptive
Relevance results. Added _meta optional field to the CurationResult type.
This commit is contained in:
Efe Gürkan YALAMAN 2022-01-13 22:22:51 +01:00 committed by GitHub
parent 3819b3bd21
commit c99dbe301c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 13 deletions

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { Result } from '../../../result/types';
import { Result, ResultMeta } from '../../../result/types';
import { CurationResult } from '../../types';
/**
@ -19,19 +19,32 @@ import { CurationResult } from '../../types';
* remove this file when that happens
*/
const mergeMetas = (partialMeta: ResultMeta, secondPartialMeta: ResultMeta): ResultMeta => {
return {
...(partialMeta || {}),
...secondPartialMeta,
};
};
export const convertToResultFormat = (document: CurationResult): Result => {
const result = {} as Result;
// Convert `key: 'value'` into `key: { raw: 'value' }`
Object.entries(document).forEach(([key, value]) => {
result[key] = {
raw: value,
snippet: null, // Don't try to provide a snippet, we can't really guesstimate it
};
// don't convert _meta if exists
if (key === '_meta') {
result[key] = value as ResultMeta;
} else {
result[key] = {
raw: value,
snippet: null, // Don't try to provide a snippet, we can't really guesstimate it
};
}
});
// Add the _meta obj needed by Result
result._meta = convertIdToMeta(document.id);
const convertedMetaObj = convertIdToMeta(document.id);
result._meta = mergeMetas(result._meta, convertedMetaObj);
return result;
};

View file

@ -6,7 +6,7 @@
*/
import { Meta } from '../../../../../common/types';
import { Result } from '../result/types';
import { Result, ResultMeta } from '../result/types';
export interface CurationSuggestion {
query: string;
@ -44,5 +44,6 @@ export interface CurationsAPIResponse {
export interface CurationResult {
// TODO: Consider updating our internal API to return more standard Result data in the future
id: string;
[key: string]: string | string[];
_meta?: ResultMeta;
[key: string]: string | string[] | ResultMeta | undefined;
}

View file

@ -51,6 +51,7 @@ describe('CurationResultPanel', () => {
resultPosition: 1,
isMetaEngine: true,
schemaForTypeHighlights: values.engine.schema,
showClick: true,
});
});

View file

@ -79,6 +79,7 @@ export const CurationResultPanel: React.FC<Props> = ({ variant, results }) => {
isMetaEngine={isMetaEngine}
schemaForTypeHighlights={engine.schema}
resultPosition={index + 1}
showClick
/>
</EuiFlexItem>
))

View file

@ -33,6 +33,7 @@ interface Props {
schemaForTypeHighlights?: Schema;
actions?: ResultAction[];
dragHandleProps?: DraggableProvidedDragHandleProps;
showClick?: boolean;
}
const RESULT_CUTOFF = 5;
@ -46,6 +47,7 @@ export const Result: React.FC<Props> = ({
actions = [],
dragHandleProps,
resultPosition,
showClick = false,
}) => {
const [isOpen, setIsOpen] = useState(false);
@ -57,7 +59,6 @@ export const Result: React.FC<Props> = ({
[result]
);
const numResults = resultFields.length;
const typeForField = (fieldName: string) => {
if (schemaForTypeHighlights) return schemaForTypeHighlights[fieldName];
};
@ -103,6 +104,7 @@ export const Result: React.FC<Props> = ({
documentLink={documentLink}
actions={actions}
resultPosition={resultPosition}
showClick={showClick}
/>
{resultFields
.slice(0, isOpen ? resultFields.length : RESULT_CUTOFF)

View file

@ -24,6 +24,7 @@ describe('ResultHeader', () => {
};
const props = {
showScore: false,
showClick: false,
isMetaEngine: false,
resultMeta,
actions: [],
@ -69,6 +70,18 @@ describe('ResultHeader', () => {
});
});
describe('clicks', () => {
it('renders clicks if showClick is true', () => {
const wrapper = shallow(<ResultHeader {...props} showClick />);
expect(wrapper.find('[data-test-subj="ResultClicks"]').exists()).toBe(true);
});
it(' does not render clicks if showClick is false', () => {
const wrapper = shallow(<ResultHeader {...props} showClick={false} />);
expect(wrapper.find('[data-test-subj="ResultClicks"]').exists()).toBe(false);
});
});
describe('engine', () => {
it('renders engine name if this is a meta engine', () => {
const wrapper = shallow(<ResultHeader {...props} isMetaEngine />);

View file

@ -24,6 +24,7 @@ interface Props {
actions: ResultAction[];
documentLink?: string;
resultPosition?: number;
showClick: boolean;
}
export const ResultHeader: React.FC<Props> = ({
@ -33,6 +34,7 @@ export const ResultHeader: React.FC<Props> = ({
actions,
documentLink,
resultPosition,
showClick,
}) => {
return (
<header className="appSearchResultHeader">
@ -65,6 +67,16 @@ export const ResultHeader: React.FC<Props> = ({
type="id"
/>
</EuiFlexItem>
{showClick && (
<EuiFlexItem grow={false}>
<ResultHeaderItem
data-test-subj="ResultClicks"
field="clicks"
value={resultMeta.clicks}
type="clicks"
/>
</EuiFlexItem>
)}
{showScore && (
<EuiFlexItem grow={false}>
<ResultHeaderItem

View file

@ -7,6 +7,8 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import './result_header_item.scss';
import { EuiLinkTo } from '../../../shared/react_router_helpers/eui_components';
@ -16,7 +18,7 @@ import { TruncatedContent } from '../../../shared/truncate';
interface Props {
field: string;
value?: string | number;
type: 'id' | 'score' | 'string';
type: 'id' | 'score' | 'string' | 'clicks';
href?: string;
}
@ -27,7 +29,15 @@ export const ResultHeaderItem: React.FC<Props> = ({ field, type, value, href })
if (typeof value === 'string') {
formattedValue = value;
} else if (typeof value === 'number') {
formattedValue = parseFloat((value as number).toFixed(2)).toString();
if (type === 'clicks') {
formattedValue = i18n.translate('xpack.enterpriseSearch.appSearch.result.clicks', {
defaultMessage: '{clicks} Clicks',
values: { clicks: value },
description: 'This is click count for Adaptive Relevance suggestion results',
});
} else {
formattedValue = parseFloat((value as number).toFixed(2)).toString();
}
}
const HeaderItemContent = () => (
@ -45,8 +55,16 @@ export const ResultHeaderItem: React.FC<Props> = ({ field, type, value, href })
type === 'score' && 'appSearchResultHeaderItem__score'
}`}
>
<TruncatedContent content={`${field}:`} length={MAX_CHARACTER_LENGTH} tooltipType="title" />
&nbsp;
{type !== 'clicks' && (
<>
<TruncatedContent
content={`${field}:`}
length={MAX_CHARACTER_LENGTH}
tooltipType="title"
/>
&nbsp;
</>
)}
{href ? (
<EuiLinkTo to={href}>
<HeaderItemContent />

View file

@ -22,6 +22,7 @@ export interface ResultMeta {
id: string;
score?: number;
engine: string;
clicks?: number;
}
// A search result item