Skip to content
Snippets Groups Projects
Commit d4036235 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '186-min-251-clicking-on-a-protein-annotation' into 'development'

Resolve "[MIN-251] Clicking on a protein: annotation"

See merge request !354
parents 820ea6d3 3e0868ff
No related branches found
No related tags found
1 merge request!354Resolve "[MIN-251] Clicking on a protein: annotation"
Pipeline #99576 passed
Showing
with 4 additions and 309 deletions
......@@ -7,7 +7,6 @@ import {
import { render, screen } from '@testing-library/react';
import { newReactionFixture } from '@/models/fixtures/newReactionFixture';
import { referenceFixture } from '@/models/fixtures/referenceFixture';
import { DEFAULT_REFERENCE_SOURCE } from './ReactionDrawer.constants';
import { ReactionDrawer } from './ReactionDrawer.component';
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
......@@ -61,14 +60,10 @@ describe('ReactionDrawer - component', () => {
);
const referencesTextHref: [string, string][] = filteredReferences.map(ref => [
`${ref.type} (${ref.id})`,
`${ref.type} (${ref.resource})`,
ref.link as string,
]);
const referencesSources: string[] = filteredReferences.map(
ref => ref.annotatorClassName || DEFAULT_REFERENCE_SOURCE,
);
beforeEach(() =>
renderComponent({
reactions: {
......@@ -99,10 +94,6 @@ describe('ReactionDrawer - component', () => {
expect(screen.getByText('Annotations:')).toBeInTheDocument();
});
it.each(referencesSources)('should show drawer reaction source for source=%s', source => {
expect(screen.getByText(`Source: ${source}`, { exact: false })).toBeInTheDocument();
});
it.each(referencesTextHref)(
'should show drawer reaction reference with text=%s, href=%s',
(refText, href) => {
......
import {
currentDrawerReactionGroupedReferencesSelector,
currentDrawerReactionSelector,
} from '@/redux/reactions/reactions.selector';
import { currentDrawerReactionSelector } from '@/redux/reactions/reactions.selector';
import { DrawerHeading } from '@/shared/DrawerHeading';
import { useSelector } from 'react-redux';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
......@@ -10,12 +7,11 @@ import { CommentItem } from '@/components/Map/Drawer/BioEntityDrawer/Comments/Co
import { ZERO } from '@/constants/common';
import ReactionTypeEnum from '@/utils/reaction/ReactionTypeEnum';
import React from 'react';
import { ReferenceGroup } from './ReferenceGroup';
import { AnnotationItemList } from '@/components/Map/Drawer/BioEntityDrawer/AnnotationItem/AnnotationItemList.component';
import { ConnectedBioEntitiesList } from './ConnectedBioEntitiesList';
export const ReactionDrawer = (): React.ReactNode => {
const reaction = useSelector(currentDrawerReactionSelector);
const referencesGrouped = useSelector(currentDrawerReactionGroupedReferencesSelector);
const commentsData = useAppSelector(currentDrawerReactionCommentsSelector);
......@@ -48,10 +44,7 @@ export const ReactionDrawer = (): React.ReactNode => {
/>
)}
<h3 className="font-semibold">Annotations:</h3>
{referencesGrouped.map(group => (
<ReferenceGroup key={group.source} group={group} />
))}
<AnnotationItemList references={reaction.references} />
<hr className="border-b border-b-divide" />
<ConnectedBioEntitiesList />
{isCommentAvailable && <div className="font-bold"> Comments</div>}
......
export const DEFAULT_REFERENCE_SOURCE = 'Annotated by curator';
import { StoreType } from '@/redux/store';
import { ReferenceFiltered } from '@/types/reference';
import {
InitialStoreState,
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { render, screen } from '@testing-library/react';
import { Props, ReferenceGroup } from './ReferenceGroup.component';
const renderComponent = (
props: Props,
initialStoreState: InitialStoreState = {},
): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
return (
render(
<Wrapper>
<ReferenceGroup {...props} />
</Wrapper>,
),
{
store,
}
);
};
describe('ReactionDrawer - component', () => {
beforeEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
const singleReference = {
link: 'https://www.ncbi.nlm.nih.gov/pubmed/24448649',
article: {
title:
'The nutrient-responsive transcription factor TFE3 promotes autophagy, lysosomal biogenesis, and clearance of cellular debris.',
authors: [
'Martina JA',
' Diab HI',
' Lishu L',
' Jeong-A L',
' Patange S',
' Raben N',
' Puertollano R.',
],
journal: 'Science signaling',
year: 2014,
link: 'https://www.ncbi.nlm.nih.gov/pubmed/24448649',
pubmedId: '24448649',
citationCount: 321,
},
type: 'PUBMED',
resource: '24448649',
id: 154973,
annotatorClassName: '',
};
const cases: [string, ReferenceFiltered[]][] = [
['', [singleReference]],
[
'source1',
[
{
...singleReference,
annotatorClassName: 'source1',
id: 1,
},
{
...singleReference,
annotatorClassName: 'source1',
id: 2,
},
],
],
[
'source2',
[
{
...singleReference,
annotatorClassName: 'source2',
id: 3,
},
],
],
];
it.each(cases)('should show reference group with source=%s', (source, references) => {
const referencesTextHref: [string, string][] = references.map(ref => [
`${ref.type} (${ref.id})`,
ref.link as string,
]);
renderComponent({
group: {
source,
references,
},
});
referencesTextHref.forEach(([refText, href]) => {
const linkReferenceSpan = screen.getByText(refText, { exact: false });
const linkReferenceAnchor = linkReferenceSpan.closest('a');
expect(linkReferenceSpan).toBeInTheDocument();
expect(linkReferenceAnchor).toBeInTheDocument();
expect(linkReferenceAnchor?.href).toBe(`${href}`);
});
});
});
import { Icon } from '@/shared/Icon';
import { ReferenceGroup as ReferenceGroupType } from '@/types/reference';
import { DEFAULT_REFERENCE_SOURCE } from '../ReactionDrawer.constants';
export interface Props {
group: ReferenceGroupType;
}
export const ReferenceGroup = ({ group: { source, references } }: Props): JSX.Element => (
<>
<h3 className="font-semibold">Source: {source || DEFAULT_REFERENCE_SOURCE}</h3>
{references.map(({ id, link, type }) => (
<a key={id} href={link} target="_blank">
<div className="flex justify-between">
<span>{`${type} (${id})`}</span>
<Icon name="arrow" className="h-6 w-6 fill-font-500" />
</div>
</a>
))}
</>
);
export { ReferenceGroup } from './ReferenceGroup.component';
......@@ -4,8 +4,6 @@ import { commentReactionSelector } from '@/redux/comment/comment.selectors';
import { currentDrawerReactionIdSelector } from '../drawer/drawer.selectors';
import { currentModelIdSelector } from '../models/models.selectors';
import { rootSelector } from '../root/root.selectors';
import { getReferencesWithoutEmptyLink } from './utils/getFilteredReferences';
import { getReferencesGroupedBySource } from './utils/getGroupedReferences';
export const reactionsSelector = createSelector(rootSelector, state => state.reactions);
......@@ -34,11 +32,3 @@ export const currentDrawerReactionSelector = createSelector(
return reactions.find(({ id }) => id === currentDrawerReactionId);
},
);
export const currentDrawerReactionGroupedReferencesSelector = createSelector(
currentDrawerReactionSelector,
reaction => {
const referencesFiltered = getReferencesWithoutEmptyLink(reaction);
return getReferencesGroupedBySource(referencesFiltered);
},
);
import {
REFERENCES_MOCK_ALL_INVALID,
REFERENCES_MOCK_ALL_VALID,
} from '@/models/mocks/referencesMock';
import { ReferenceFiltered } from '@/types/reference';
import { NewReaction } from '@/types/models';
import { getReferencesWithoutEmptyLink } from './getFilteredReferences';
describe('getFilteredReferences - subUtil', () => {
const cases: [Pick<NewReaction, 'references'>, ReferenceFiltered[]][] = [
[
{
references: REFERENCES_MOCK_ALL_VALID,
},
REFERENCES_MOCK_ALL_VALID as ReferenceFiltered[],
],
[
{
references: REFERENCES_MOCK_ALL_INVALID,
},
[],
],
[
{
references: [...REFERENCES_MOCK_ALL_VALID, ...REFERENCES_MOCK_ALL_INVALID],
},
REFERENCES_MOCK_ALL_VALID as ReferenceFiltered[],
],
];
it.each(cases)('should return valid filtered references', (reaction, result) => {
expect(getReferencesWithoutEmptyLink(reaction)).toStrictEqual(result);
});
});
import { NewReaction } from '@/types/models';
import { ReferenceFiltered } from '@/types/reference';
type InputReaction = Pick<NewReaction, 'references'>;
export const getReferencesWithoutEmptyLink = (
reaction: InputReaction | undefined,
): ReferenceFiltered[] =>
(reaction?.references || []).filter(
(ref): ref is ReferenceFiltered => ref.link !== null && ref.link !== undefined,
);
import { ReferenceFiltered } from '@/types/reference';
import { getReferencesGroupedBySource } from './getGroupedReferences';
describe('getGroupedReferences - util', () => {
const singleReference = {
link: 'https://www.ncbi.nlm.nih.gov/pubmed/24448649',
article: {
title:
'The nutrient-responsive transcription factor TFE3 promotes autophagy, lysosomal biogenesis, and clearance of cellular debris.',
authors: [
'Martina JA',
' Diab HI',
' Lishu L',
' Jeong-A L',
' Patange S',
' Raben N',
' Puertollano R.',
],
journal: 'Science signaling',
year: 2014,
link: 'https://www.ncbi.nlm.nih.gov/pubmed/24448649',
pubmedId: '24448649',
citationCount: 321,
},
type: 'PUBMED',
resource: '24448649',
id: 154973,
annotatorClassName: '',
};
const cases = [
[[], []],
[
[singleReference],
[
{
source: '',
references: [singleReference],
},
],
],
[
[
{
...singleReference,
annotatorClassName: 'source1',
},
{
...singleReference,
annotatorClassName: 'source1',
},
{
...singleReference,
annotatorClassName: 'source2',
},
],
[
{
source: 'source1',
references: [
{
...singleReference,
annotatorClassName: 'source1',
},
{
...singleReference,
annotatorClassName: 'source1',
},
],
},
{
source: 'source2',
references: [
{
...singleReference,
annotatorClassName: 'source2',
},
],
},
],
],
];
it.each(cases)('should return correct grouped references', (references, referencesGrouped) =>
expect(getReferencesGroupedBySource(references as ReferenceFiltered[])).toMatchObject(
referencesGrouped,
),
);
});
import { ReferenceFiltered, ReferenceGrouped } from '@/types/reference';
import { groupBy } from '@/utils/array/groupBy';
export const getReferencesGroupedBySource = (references: ReferenceFiltered[]): ReferenceGrouped => {
const referencesGroupedObject = groupBy(references, ref => ref.annotatorClassName);
return Object.entries(referencesGroupedObject).map(([source, refs]) => ({
source,
references: refs,
}));
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment