Skip to content

Commit 76d031b

Browse files
committed
Added Thumbnails to Search UI
1 parent 9dc303a commit 76d031b

7 files changed

Lines changed: 104 additions & 1 deletion

File tree

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/search_ui_form.test.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('SearchUIForm', () => {
3939
onSortFieldsChange: jest.fn(),
4040
onTitleFieldChange: jest.fn(),
4141
onUrlFieldChange: jest.fn(),
42+
onThumbnailFieldChange: jest.fn(),
4243
};
4344

4445
beforeAll(() => {
@@ -52,6 +53,7 @@ describe('SearchUIForm', () => {
5253
expect(wrapper.find('[data-test-subj="selectFilters"]').exists()).toBe(true);
5354
expect(wrapper.find('[data-test-subj="selectSort"]').exists()).toBe(true);
5455
expect(wrapper.find('[data-test-subj="selectUrl"]').exists()).toBe(true);
56+
expect(wrapper.find('[data-test-subj="selectThumbnail"]').exists()).toBe(true);
5557
});
5658

5759
describe('title field', () => {
@@ -112,6 +114,35 @@ describe('SearchUIForm', () => {
112114
});
113115
});
114116

117+
describe('thumbnail field', () => {
118+
beforeEach(() => jest.clearAllMocks());
119+
const subject = () => shallow(<SearchUIForm />).find('[data-test-subj="selectThumbnail"]');
120+
121+
it('renders with its value set from state', () => {
122+
setMockValues({
123+
...values,
124+
thumbnailField: 'foo',
125+
});
126+
127+
expect(subject().prop('value')).toBe('foo');
128+
});
129+
130+
it('updates state with new value when changed', () => {
131+
subject().simulate('change', { target: { value: 'foo' } });
132+
expect(actions.onThumbnailFieldChange).toHaveBeenCalledWith('foo');
133+
});
134+
135+
it('updates active field in state on focus', () => {
136+
subject().simulate('focus');
137+
expect(actions.onActiveFieldChange).toHaveBeenCalledWith(ActiveField.Thumb);
138+
});
139+
140+
it('removes active field in state on blur', () => {
141+
subject().simulate('blur');
142+
expect(actions.onActiveFieldChange).toHaveBeenCalledWith(ActiveField.None);
143+
});
144+
});
145+
115146
describe('filters field', () => {
116147
beforeEach(() => jest.clearAllMocks());
117148
const subject = () => shallow(<SearchUIForm />).find('[data-test-subj="selectFilters"]');

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/search_ui_form.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
URL_FIELD_LABEL,
2323
URL_FIELD_HELP_TEXT,
2424
GENERATE_PREVIEW_BUTTON_LABEL,
25+
THUMBNAIL_FIELD_LABEL,
26+
THUMBNAIL_FIELD_HELP_TEXT,
2527
} from '../i18n';
2628
import { SearchUILogic } from '../search_ui_logic';
2729
import { ActiveField } from '../types';
@@ -36,6 +38,7 @@ export const SearchUIForm: React.FC = () => {
3638
validFacetFields,
3739
titleField,
3840
urlField,
41+
thumbnailField,
3942
facetFields,
4043
sortFields,
4144
} = useValues(SearchUILogic);
@@ -45,11 +48,13 @@ export const SearchUIForm: React.FC = () => {
4548
onSortFieldsChange,
4649
onTitleFieldChange,
4750
onUrlFieldChange,
51+
onThumbnailFieldChange,
4852
} = useActions(SearchUILogic);
4953

5054
const previewHref = generatePreviewUrl({
5155
titleField,
5256
urlField,
57+
thumbnailField,
5358
facets: facetFields,
5459
sortFields,
5560
});
@@ -69,6 +74,7 @@ export const SearchUIForm: React.FC = () => {
6974
const facetOptionFields = formatMultiOptions(validFacetFields);
7075
const selectedTitleOption = formatSelectOption(titleField);
7176
const selectedURLOption = formatSelectOption(urlField);
77+
const selectedThumbnailOption = formatSelectOption(thumbnailField);
7278
const selectedSortOptions = formatMultiOptions(sortFields);
7379
const selectedFacetOptions = formatMultiOptions(facetFields);
7480

@@ -112,7 +118,6 @@ export const SearchUIForm: React.FC = () => {
112118
data-test-subj="selectSort"
113119
/>
114120
</EuiFormRow>
115-
116121
<EuiFormRow label={URL_FIELD_LABEL} helpText={URL_FIELD_HELP_TEXT} fullWidth>
117122
<EuiSelect
118123
disabled={dataLoading}
@@ -126,6 +131,19 @@ export const SearchUIForm: React.FC = () => {
126131
data-test-subj="selectUrl"
127132
/>
128133
</EuiFormRow>
134+
<EuiFormRow label={THUMBNAIL_FIELD_LABEL} helpText={THUMBNAIL_FIELD_HELP_TEXT} fullWidth>
135+
<EuiSelect
136+
disabled={dataLoading}
137+
options={optionFields}
138+
value={selectedThumbnailOption && selectedThumbnailOption.value}
139+
onChange={(e) => onThumbnailFieldChange(e.target.value)}
140+
fullWidth
141+
onFocus={() => onActiveFieldChange(ActiveField.Thumb)}
142+
onBlur={() => onActiveFieldChange(ActiveField.None)}
143+
hasNoInitialSelection
144+
data-test-subj="selectThumbnail"
145+
/>
146+
</EuiFormRow>
129147
<EuiButton
130148
disabled={dataLoading}
131149
type="submit"

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/components/search_ui_graphic.scss

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,27 @@
185185
}
186186
}
187187
}
188+
&.activeThumb {
189+
#results {
190+
.outerBox {
191+
fill: $euiColorEmptyShade;
192+
stroke: $euiColorPrimary;
193+
stroke-width: 1px;
194+
}
195+
.url {
196+
fill: $euiColorPrimary;
197+
opacity: .1;
198+
}
199+
.titleBox {
200+
fill: $euiColorEmptyShade;
201+
}
202+
.titleCopy {
203+
fill: $euiColorPrimary;
204+
opacity: .1;
205+
}
206+
.shoe {
207+
fill: $euiColorPrimary;
208+
}
209+
}
210+
}
188211
}

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/i18n.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,18 @@ export const URL_FIELD_LABEL = i18n.translate(
4242
'xpack.enterpriseSearch.appSearch.engine.searchUI.urlFieldLabel',
4343
{ defaultMessage: 'URL field (Optional)' }
4444
);
45+
export const THUMBNAIL_FIELD_LABEL = i18n.translate(
46+
'xpack.enterpriseSearch.appSearch.engine.searchUI.thumbnailFieldLabel',
47+
{ defaultMessage: 'Thumbnail field (Optional)' }
48+
);
4549
export const URL_FIELD_HELP_TEXT = i18n.translate(
4650
'xpack.enterpriseSearch.appSearch.engine.searchUI.urlFieldHelpText',
4751
{ defaultMessage: "Used as a result's link target, if applicable" }
4852
);
53+
export const THUMBNAIL_FIELD_HELP_TEXT = i18n.translate(
54+
'xpack.enterpriseSearch.appSearch.engine.searchUI.thumbnailFieldHelpText',
55+
{ defaultMessage: 'Used to show a thumbnail image' }
56+
);
4957
export const GENERATE_PREVIEW_BUTTON_LABEL = i18n.translate(
5058
'xpack.enterpriseSearch.appSearch.engine.searchUI.generatePreviewButtonLabel',
5159
{ defaultMessage: 'Generate search experience' }

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe('SearchUILogic', () => {
3030
validFacetFields: [],
3131
titleField: '',
3232
urlField: '',
33+
thumbnailField: '',
3334
facetFields: [],
3435
sortFields: [],
3536
activeField: ActiveField.None,
@@ -93,6 +94,17 @@ describe('SearchUILogic', () => {
9394
});
9495
});
9596

97+
describe('onThumbnailFieldChange', () => {
98+
it('sets the thumbnailField value', () => {
99+
mount({ thumbnailField: '' });
100+
SearchUILogic.actions.onThumbnailFieldChange('foo');
101+
expect(SearchUILogic.values).toEqual({
102+
...DEFAULT_VALUES,
103+
thumbnailField: 'foo',
104+
});
105+
});
106+
});
107+
96108
describe('onFacetFieldsChange', () => {
97109
it('sets the facetFields value', () => {
98110
mount({ facetFields: [] });

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface InitialFieldValues {
2020
validSortFields: string[];
2121
validFacetFields: string[];
2222
urlField?: string;
23+
thumbnailField?: string;
2324
titleField?: string;
2425
}
2526
interface SearchUIActions {
@@ -30,6 +31,7 @@ interface SearchUIActions {
3031
onSortFieldsChange(sortFields: string[]): { sortFields: string[] };
3132
onTitleFieldChange(titleField: string): { titleField: string };
3233
onUrlFieldChange(urlField: string): { urlField: string };
34+
onThumbnailFieldChange(thumbnailField: string): { thumbnailField: string };
3335
}
3436

3537
interface SearchUIValues {
@@ -39,6 +41,7 @@ interface SearchUIValues {
3941
validFacetFields: string[];
4042
titleField: string;
4143
urlField: string;
44+
thumbnailField: string;
4245
facetFields: string[];
4346
sortFields: string[];
4447
activeField: ActiveField;
@@ -54,6 +57,7 @@ export const SearchUILogic = kea<MakeLogicType<SearchUIValues, SearchUIActions>>
5457
onSortFieldsChange: (sortFields) => ({ sortFields }),
5558
onTitleFieldChange: (titleField) => ({ titleField }),
5659
onUrlFieldChange: (urlField) => ({ urlField }),
60+
onThumbnailFieldChange: (thumbnailField) => ({ thumbnailField }),
5761
}),
5862
reducers: () => ({
5963
dataLoading: [
@@ -79,6 +83,12 @@ export const SearchUILogic = kea<MakeLogicType<SearchUIValues, SearchUIActions>>
7983
onFieldDataLoaded: (_, { urlField }) => urlField || '',
8084
},
8185
],
86+
thumbnailField: [
87+
'',
88+
{
89+
onThumbnailFieldChange: (_, { thumbnailField }) => thumbnailField,
90+
},
91+
],
8292
facetFields: [[], { onFacetFieldsChange: (_, { facetFields }) => facetFields }],
8393
sortFields: [[], { onSortFieldsChange: (_, { sortFields }) => sortFields }],
8494
activeField: [ActiveField.None, { onActiveFieldChange: (_, { activeField }) => activeField }],

x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export enum ActiveField {
1010
Filter = 'Filter',
1111
Sort = 'Sort',
1212
Url = 'Url',
13+
Thumb = 'Thumb',
1314
None = '',
1415
}

0 commit comments

Comments
 (0)