diff --git a/__tests__/src/components/SearchHit.test.js b/__tests__/src/components/SearchHit.test.js index 3e4f62085f893895f20d3862ba0327dd602e45c8..ba11e0b36a0d660d67a8405ea431972148887d57 100644 --- a/__tests__/src/components/SearchHit.test.js +++ b/__tests__/src/components/SearchHit.test.js @@ -35,4 +35,18 @@ describe('SearchHit', () => { wrapper.find('WithStyles(ForwardRef(ListItem))').simulate('click'); expect(selectContentSearchAnnotation).toHaveBeenCalledWith('window', ['foo']); }); + + describe('Annotation Labels', () => { + it('renders the annotationLabel if present', () => { + const wrapper = createWrapper({ annotationLabel: 'The Anno Label' }); + + expect(wrapper.find('WithStyles(ForwardRef(Typography))[variant="subtitle2"][children="The Anno Label"]').length).toEqual(1); + }); + + it('does not render the typography if no annotation label is present', () => { + const wrapper = createWrapper(); + + expect(wrapper.find('WithStyles(ForwardRef(Typography))[variant="subtitle2"]').length).toEqual(0); + }); + }); }); diff --git a/__tests__/src/selectors/searches.test.js b/__tests__/src/selectors/searches.test.js index 33603b41e859039ee9759db52e7b5f7be658c29b..e50ae15fd45e2e8f00c51bb5968f10f951bf468e 100644 --- a/__tests__/src/selectors/searches.test.js +++ b/__tests__/src/selectors/searches.test.js @@ -5,6 +5,8 @@ import { getSelectedContentSearchAnnotationIds, getSelectedContentSearchAnnotations, getSearchAnnotationForCompanionWindow, + getResourceAnnotationForSearchHit, + getResourceAnnotationLabel, } from '../../../src/state/selectors'; describe('getSearchResultsForWindow', () => { @@ -186,3 +188,80 @@ describe('getSelectedContentSearchAnnotations', () => { ).toEqual([]); }); }); + +describe('getResourceAnnotationForSearchHit', () => { + const companionWindowId = 'cwid'; + const annoId = 'annoId2'; + it('returns the resource annotation connected to the hit by ID', () => { + const state = { + searches: { + a: { + [companionWindowId]: { + json: { + '@id': 'yolo', + resources: [{ '@id': annoId }], + }, + }, + }, + }, + }; + + expect( + getResourceAnnotationForSearchHit( + state, { annotationUri: annoId, companionWindowId, windowId: 'a' }, + ).resource['@id'], + ).toEqual(annoId); + }); +}); + +describe('getResourceAnnotationLabel', () => { + const companionWindowId = 'cwid'; + const annoId = 'annoId2'; + it('returns the label from a LanguageMap JSON object', () => { + const state = { + companionWindows: { + [companionWindowId]: { locale: 'en' }, + }, + searches: { + a: { + [companionWindowId]: { + json: { + '@id': 'yolo', + resources: [{ + '@id': annoId, + label: { '@language': 'en', '@value': 'The Annotation Label' }, + }], + }, + }, + }, + }, + }; + + expect( + getResourceAnnotationLabel( + state, { annotationUri: annoId, companionWindowId, windowId: 'a' }, + ), + ).toEqual(['The Annotation Label']); + }); + + it('returns an empty array if the annotation resource does not have a label (to be consistent w/ the return of LanguageMap.parse)', () => { + const state = { + companionWindows: { + [companionWindowId]: { locale: 'en' }, + }, + searches: { + a: { + [companionWindowId]: { + json: { '@id': 'yolo', resources: [{ '@id': annoId }] }, + }, + }, + }, + }; + + expect( + getResourceAnnotationLabel( + state, { annotationUri: annoId, companionWindowId, windowId: 'a' }, + ), + ).toEqual([]); + }); +}); diff --git a/src/components/SearchHit.js b/src/components/SearchHit.js index 8e81154b3f1c57b6a720270e1a0f530ba66c2034..6fed57af1d743364425985cc076651424ffaf41b 100644 --- a/src/components/SearchHit.js +++ b/src/components/SearchHit.js @@ -31,6 +31,7 @@ export class SearchHit extends Component { render() { const { adjacent, + annotationLabel, canvasLabel, classes, hit, @@ -65,6 +66,9 @@ export class SearchHit extends Component { <Chip component="span" label={index + 1} className={classes.hitCounter} /> {canvasLabel} </Typography> + {annotationLabel && ( + <Typography variant="subtitle2">{annotationLabel}</Typography> + )} <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.before} /> {' '} <strong> @@ -86,6 +90,7 @@ export class SearchHit extends Component { SearchHit.propTypes = { adjacent: PropTypes.bool, + annotationLabel: PropTypes.string, canvasLabel: PropTypes.string, classes: PropTypes.objectOf(PropTypes.string), focused: PropTypes.bool, @@ -105,6 +110,7 @@ SearchHit.propTypes = { SearchHit.defaultProps = { adjacent: false, + annotationLabel: undefined, canvasLabel: undefined, classes: {}, focused: false, diff --git a/src/containers/SearchHit.js b/src/containers/SearchHit.js index 3cb7abf0007512ac9a481a8e6c23bb3cc1d7575e..12401c9dcca13029ebdd7a4c459ee772b76ec2d5 100644 --- a/src/containers/SearchHit.js +++ b/src/containers/SearchHit.js @@ -7,8 +7,9 @@ import { SearchHit } from '../components/SearchHit'; import * as actions from '../state/actions'; import { getCanvasLabel, - getSearchAnnotationForCompanionWindow, getSelectedCanvases, + getResourceAnnotationForSearchHit, + getResourceAnnotationLabel, getSelectedContentSearchAnnotationIds, } from '../state/selectors'; @@ -18,17 +19,17 @@ import { * @private */ const mapStateToProps = (state, { hit, companionWindowId, windowId }) => { - const annotation = getSearchAnnotationForCompanionWindow( - state, { companionWindowId, windowId }, + const hitAnnotation = getResourceAnnotationForSearchHit( + state, { annotationUri: hit.annotations[0], companionWindowId, windowId }, + ); + const annotationLabel = getResourceAnnotationLabel( + state, { annotationUri: hit.annotations[0], companionWindowId, windowId }, ); - - const resourceAnnotations = annotation.resources; - const hitAnnotation = resourceAnnotations.find(r => r.id === hit.annotations[0]); - const selectedCanvasIds = getSelectedCanvases(state, { windowId }).map(canvas => canvas.id); return { adjacent: selectedCanvasIds.includes(hitAnnotation.targetId), + annotationLabel: annotationLabel[0], canvasLabel: hitAnnotation && getCanvasLabel(state, { canvasId: hitAnnotation.targetId, windowId, diff --git a/src/state/selectors/searches.js b/src/state/selectors/searches.js index 165c1c52dd564908d31a62d3f75de85c2dbf3f26..f576025172757fe0b377253241484ffbfe77d2e9 100644 --- a/src/state/selectors/searches.js +++ b/src/state/selectors/searches.js @@ -1,6 +1,8 @@ import { createSelector } from 'reselect'; +import { LanguageMap } from 'manifesto.js'; import Annotation from '../../lib/Annotation'; import { getWindow } from './windows'; +import { getManifestLocale } from './manifests'; export const getSearchResultsForWindow = createSelector( [ @@ -83,3 +85,27 @@ export const getSelectedContentSearchAnnotations = createSelector( ), })).filter(val => val.resources.length > 0), ); + +export const getResourceAnnotationForSearchHit = createSelector( + [ + getSearchAnnotationForCompanionWindow, + (state, { annotationUri }) => annotationUri, + ], + (searchAnnotations, annotationUri) => searchAnnotations.resources.find( + r => r.id === annotationUri, + ), +); + +export const getResourceAnnotationLabel = createSelector( + [ + getResourceAnnotationForSearchHit, + getManifestLocale, + ], + (resourceAnnotation, locale) => { + if ( + !(resourceAnnotation && resourceAnnotation.resource && resourceAnnotation.resource.label) + ) return []; + + return LanguageMap.parse(resourceAnnotation.resource.label, locale).map(label => label.value); + }, +);