[Enterprise Search] Added Thumbnails to Search UI (#104199) (#105663)

Co-authored-by: Jason Stoltzfus <jastoltz24@gmail.com>
This commit is contained in:
Kibana Machine 2021-07-14 17:50:08 -04:00 committed by GitHub
parent 37f0e1e168
commit 409a0c69f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 104 additions and 1 deletions

View file

@ -39,6 +39,7 @@ describe('SearchUIForm', () => {
onSortFieldsChange: jest.fn(),
onTitleFieldChange: jest.fn(),
onUrlFieldChange: jest.fn(),
onThumbnailFieldChange: jest.fn(),
};
beforeAll(() => {
@ -52,6 +53,7 @@ describe('SearchUIForm', () => {
expect(wrapper.find('[data-test-subj="selectFilters"]').exists()).toBe(true);
expect(wrapper.find('[data-test-subj="selectSort"]').exists()).toBe(true);
expect(wrapper.find('[data-test-subj="selectUrl"]').exists()).toBe(true);
expect(wrapper.find('[data-test-subj="selectThumbnail"]').exists()).toBe(true);
});
describe('title field', () => {
@ -112,6 +114,35 @@ describe('SearchUIForm', () => {
});
});
describe('thumbnail field', () => {
beforeEach(() => jest.clearAllMocks());
const subject = () => shallow(<SearchUIForm />).find('[data-test-subj="selectThumbnail"]');
it('renders with its value set from state', () => {
setMockValues({
...values,
thumbnailField: 'foo',
});
expect(subject().prop('value')).toBe('foo');
});
it('updates state with new value when changed', () => {
subject().simulate('change', { target: { value: 'foo' } });
expect(actions.onThumbnailFieldChange).toHaveBeenCalledWith('foo');
});
it('updates active field in state on focus', () => {
subject().simulate('focus');
expect(actions.onActiveFieldChange).toHaveBeenCalledWith(ActiveField.Thumb);
});
it('removes active field in state on blur', () => {
subject().simulate('blur');
expect(actions.onActiveFieldChange).toHaveBeenCalledWith(ActiveField.None);
});
});
describe('filters field', () => {
beforeEach(() => jest.clearAllMocks());
const subject = () => shallow(<SearchUIForm />).find('[data-test-subj="selectFilters"]');

View file

@ -22,6 +22,8 @@ import {
URL_FIELD_LABEL,
URL_FIELD_HELP_TEXT,
GENERATE_PREVIEW_BUTTON_LABEL,
THUMBNAIL_FIELD_LABEL,
THUMBNAIL_FIELD_HELP_TEXT,
} from '../i18n';
import { SearchUILogic } from '../search_ui_logic';
import { ActiveField } from '../types';
@ -36,6 +38,7 @@ export const SearchUIForm: React.FC = () => {
validFacetFields,
titleField,
urlField,
thumbnailField,
facetFields,
sortFields,
} = useValues(SearchUILogic);
@ -45,11 +48,13 @@ export const SearchUIForm: React.FC = () => {
onSortFieldsChange,
onTitleFieldChange,
onUrlFieldChange,
onThumbnailFieldChange,
} = useActions(SearchUILogic);
const previewHref = generatePreviewUrl({
titleField,
urlField,
thumbnailField,
facets: facetFields,
sortFields,
});
@ -69,6 +74,7 @@ export const SearchUIForm: React.FC = () => {
const facetOptionFields = formatMultiOptions(validFacetFields);
const selectedTitleOption = formatSelectOption(titleField);
const selectedURLOption = formatSelectOption(urlField);
const selectedThumbnailOption = formatSelectOption(thumbnailField);
const selectedSortOptions = formatMultiOptions(sortFields);
const selectedFacetOptions = formatMultiOptions(facetFields);
@ -112,7 +118,6 @@ export const SearchUIForm: React.FC = () => {
data-test-subj="selectSort"
/>
</EuiFormRow>
<EuiFormRow label={URL_FIELD_LABEL} helpText={URL_FIELD_HELP_TEXT} fullWidth>
<EuiSelect
disabled={dataLoading}
@ -126,6 +131,19 @@ export const SearchUIForm: React.FC = () => {
data-test-subj="selectUrl"
/>
</EuiFormRow>
<EuiFormRow label={THUMBNAIL_FIELD_LABEL} helpText={THUMBNAIL_FIELD_HELP_TEXT} fullWidth>
<EuiSelect
disabled={dataLoading}
options={optionFields}
value={selectedThumbnailOption && selectedThumbnailOption.value}
onChange={(e) => onThumbnailFieldChange(e.target.value)}
fullWidth
onFocus={() => onActiveFieldChange(ActiveField.Thumb)}
onBlur={() => onActiveFieldChange(ActiveField.None)}
hasNoInitialSelection
data-test-subj="selectThumbnail"
/>
</EuiFormRow>
<EuiButton
disabled={dataLoading}
type="submit"

View file

@ -185,4 +185,27 @@
}
}
}
&.activeThumb {
#results {
.outerBox {
fill: $euiColorEmptyShade;
stroke: $euiColorPrimary;
stroke-width: $euiBorderWidthThin;
}
.url {
fill: $euiColorPrimary;
opacity: .1;
}
.titleBox {
fill: $euiColorEmptyShade;
}
.titleCopy {
fill: $euiColorPrimary;
opacity: .1;
}
.shoe {
fill: $euiColorPrimary;
}
}
}
}

View file

@ -42,10 +42,18 @@ export const URL_FIELD_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.searchUI.urlFieldLabel',
{ defaultMessage: 'URL field (Optional)' }
);
export const THUMBNAIL_FIELD_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.searchUI.thumbnailFieldLabel',
{ defaultMessage: 'Thumbnail field (Optional)' }
);
export const URL_FIELD_HELP_TEXT = i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.searchUI.urlFieldHelpText',
{ defaultMessage: "Used as a result's link target, if applicable" }
);
export const THUMBNAIL_FIELD_HELP_TEXT = i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.searchUI.thumbnailFieldHelpText',
{ defaultMessage: 'Provide an image URL to show a thumbnail image' }
);
export const GENERATE_PREVIEW_BUTTON_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.searchUI.generatePreviewButtonLabel',
{ defaultMessage: 'Generate search experience' }

View file

@ -30,6 +30,7 @@ describe('SearchUILogic', () => {
validFacetFields: [],
titleField: '',
urlField: '',
thumbnailField: '',
facetFields: [],
sortFields: [],
activeField: ActiveField.None,
@ -93,6 +94,17 @@ describe('SearchUILogic', () => {
});
});
describe('onThumbnailFieldChange', () => {
it('sets the thumbnailField value', () => {
mount({ thumbnailField: '' });
SearchUILogic.actions.onThumbnailFieldChange('foo');
expect(SearchUILogic.values).toEqual({
...DEFAULT_VALUES,
thumbnailField: 'foo',
});
});
});
describe('onFacetFieldsChange', () => {
it('sets the facetFields value', () => {
mount({ facetFields: [] });

View file

@ -20,6 +20,7 @@ interface InitialFieldValues {
validSortFields: string[];
validFacetFields: string[];
urlField?: string;
thumbnailField?: string;
titleField?: string;
}
interface SearchUIActions {
@ -30,6 +31,7 @@ interface SearchUIActions {
onSortFieldsChange(sortFields: string[]): { sortFields: string[] };
onTitleFieldChange(titleField: string): { titleField: string };
onUrlFieldChange(urlField: string): { urlField: string };
onThumbnailFieldChange(thumbnailField: string): { thumbnailField: string };
}
interface SearchUIValues {
@ -39,6 +41,7 @@ interface SearchUIValues {
validFacetFields: string[];
titleField: string;
urlField: string;
thumbnailField: string;
facetFields: string[];
sortFields: string[];
activeField: ActiveField;
@ -54,6 +57,7 @@ export const SearchUILogic = kea<MakeLogicType<SearchUIValues, SearchUIActions>>
onSortFieldsChange: (sortFields) => ({ sortFields }),
onTitleFieldChange: (titleField) => ({ titleField }),
onUrlFieldChange: (urlField) => ({ urlField }),
onThumbnailFieldChange: (thumbnailField) => ({ thumbnailField }),
}),
reducers: () => ({
dataLoading: [
@ -79,6 +83,12 @@ export const SearchUILogic = kea<MakeLogicType<SearchUIValues, SearchUIActions>>
onFieldDataLoaded: (_, { urlField }) => urlField || '',
},
],
thumbnailField: [
'',
{
onThumbnailFieldChange: (_, { thumbnailField }) => thumbnailField,
},
],
facetFields: [[], { onFacetFieldsChange: (_, { facetFields }) => facetFields }],
sortFields: [[], { onSortFieldsChange: (_, { sortFields }) => sortFields }],
activeField: [ActiveField.None, { onActiveFieldChange: (_, { activeField }) => activeField }],

View file

@ -10,5 +10,6 @@ export enum ActiveField {
Filter = 'Filter',
Sort = 'Sort',
Url = 'Url',
Thumb = 'Thumb',
None = '',
}