From e535723e75b7f039e99a829f96ec7b7c4a0bd5af Mon Sep 17 00:00:00 2001 From: Andrey Azov Date: Sun, 30 Jul 2023 21:59:11 +0100 Subject: [PATCH] Add "view in genome browser" button to variant zmenu (#1008) Also, moved the ZmenuAppLinks component out of the ZmenuContent component for better flexibility/composability. --- .../components/zmenu/Zmenu.scss | 11 +++-- .../components/zmenu/Zmenu.test.tsx | 8 ++- .../components/zmenu/ZmenuAppLinks.tsx | 14 +----- .../components/zmenu/ZmenuContent.tsx | 3 -- .../zmenus/GeneAndOneTranscriptZmenu.tsx | 25 +++++++--- .../components/zmenu/zmenus/VariantZmenu.tsx | 49 ++++++++++++++++--- .../genome-browser-service/types/zmenu.ts | 4 +- .../components/view-in-app/ViewInApp.tsx | 3 +- src/shared/helpers/focusObjectHelpers.ts | 9 ++++ 9 files changed, 92 insertions(+), 34 deletions(-) diff --git a/src/content/app/genome-browser/components/zmenu/Zmenu.scss b/src/content/app/genome-browser/components/zmenu/Zmenu.scss index c0db7d21ca..f7a8a6d4c5 100644 --- a/src/content/app/genome-browser/components/zmenu/Zmenu.scss +++ b/src/content/app/genome-browser/components/zmenu/Zmenu.scss @@ -36,10 +36,15 @@ color: $blue; } -.zmenuAppLinks { - display: flex; +.zmenuLinksGrid { + display: grid; + grid-template-columns: auto [app-links] 1fr; align-items: center; - justify-content: space-between; +} + +.zmenuAppLinks { + grid-column: app-links; + justify-self: end; } .zmenuToggleFooter { diff --git a/src/content/app/genome-browser/components/zmenu/Zmenu.test.tsx b/src/content/app/genome-browser/components/zmenu/Zmenu.test.tsx index 20ba8c4836..615ca2ee37 100644 --- a/src/content/app/genome-browser/components/zmenu/Zmenu.test.tsx +++ b/src/content/app/genome-browser/components/zmenu/Zmenu.test.tsx @@ -56,6 +56,12 @@ jest.mock('./ZmenuContent', () => () => ( jest.mock('./ZmenuInstantDownload', () => () => (
ZmenuInstantDownload
)); +jest.mock('./zmenus/GeneAndOneTranscriptZmenu', () => () => ( +
+ GeneAndOneTranscriptZmenu +
+)); +jest.mock('./zmenus/VariantZmenu', () => () =>
VariantZmenu
); jest.mock('./zmenus/RegulationZmenu', () => () =>
RegulationZmenu
); const chrName = faker.lorem.word(); @@ -113,7 +119,7 @@ describe('', () => { describe('rendering', () => { it('renders zmenu content', () => { const { queryByTestId } = renderComponent(); - expect(queryByTestId('zmenuContent')).toBeTruthy(); + expect(queryByTestId('gene-and-one-transcript-zmenu')).toBeTruthy(); }); }); diff --git a/src/content/app/genome-browser/components/zmenu/ZmenuAppLinks.tsx b/src/content/app/genome-browser/components/zmenu/ZmenuAppLinks.tsx index 215d7879de..eb7d0063ea 100644 --- a/src/content/app/genome-browser/components/zmenu/ZmenuAppLinks.tsx +++ b/src/content/app/genome-browser/components/zmenu/ZmenuAppLinks.tsx @@ -17,14 +17,12 @@ import React from 'react'; import * as urlFor from 'src/shared/helpers/urlHelper'; -import { parseFocusIdFromUrl } from 'src/shared/helpers/focusObjectHelpers'; import useGenomeBrowserIds from 'src/content/app/genome-browser/hooks/useGenomeBrowserIds'; import useGenomeBrowser from '../../hooks/useGenomeBrowser'; -import { ToggleButton as ToolboxToggleButton } from 'src/shared/components/toolbox'; import ViewInApp, { - LinksConfig + type LinksConfig } from 'src/shared/components/view-in-app/ViewInApp'; import styles from './Zmenu.scss'; @@ -42,12 +40,6 @@ const ZmenuAppLinks = (props: Props) => { const { changeFocusObject } = useGenomeBrowser(); const navigate = useNavigate(); - const { type: featureType } = parseFocusIdFromUrl(featureId); - - if (featureType !== 'gene') { - return null; - } - const onGenomeBrowserAppClick = () => { if (!(focusObjectIdForUrl && focusObjectId)) { return; @@ -79,10 +71,6 @@ const ZmenuAppLinks = (props: Props) => { return (
- { />

))} - ); diff --git a/src/content/app/genome-browser/components/zmenu/zmenus/GeneAndOneTranscriptZmenu.tsx b/src/content/app/genome-browser/components/zmenu/zmenus/GeneAndOneTranscriptZmenu.tsx index 51d84258c9..7ef1aa903e 100644 --- a/src/content/app/genome-browser/components/zmenu/zmenus/GeneAndOneTranscriptZmenu.tsx +++ b/src/content/app/genome-browser/components/zmenu/zmenus/GeneAndOneTranscriptZmenu.tsx @@ -20,9 +20,13 @@ import { useAppDispatch } from 'src/store'; import { changeHighlightedTrackId } from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice'; -import { ToolboxExpandableContent } from 'src/shared/components/toolbox'; +import { + ToolboxExpandableContent, + ToggleButton as ToolboxToggleButton +} from 'src/shared/components/toolbox'; import ZmenuContent from '../ZmenuContent'; import ZmenuInstantDownload from '../ZmenuInstantDownload'; +import ZmenuAppLinks from '../ZmenuAppLinks'; import type { ZmenuContentTranscript, @@ -73,11 +77,20 @@ const GeneAndOneTranscriptZmenu = (props: Props) => { }, []); const mainContent = ( - + <> + +
+ + +
+ ); const footerContent = ( diff --git a/src/content/app/genome-browser/components/zmenu/zmenus/VariantZmenu.tsx b/src/content/app/genome-browser/components/zmenu/zmenus/VariantZmenu.tsx index 457b02bb10..5b680434fb 100644 --- a/src/content/app/genome-browser/components/zmenu/zmenus/VariantZmenu.tsx +++ b/src/content/app/genome-browser/components/zmenu/zmenus/VariantZmenu.tsx @@ -16,13 +16,22 @@ import React from 'react'; +import * as urlFor from 'src/shared/helpers/urlHelper'; +import { buildFocusVariantId } from 'src/shared/helpers/focusObjectHelpers'; +import { isEnvironment, Environment } from 'src/shared/helpers/environment'; + +import useGenomeBrowserIds from 'src/content/app/genome-browser/hooks/useGenomeBrowserIds'; + import ZmenuContent from '../ZmenuContent'; +import ViewInApp from 'src/shared/components/view-in-app/ViewInApp'; import type { ZmenuPayload, ZmenuContentVariantMetadata } from 'src/content/app/genome-browser/services/genome-browser-service/types/zmenu'; +import styles from '../Zmenu.scss'; + type Props = { payload: ZmenuPayload; onDestroy: () => void; @@ -30,18 +39,46 @@ type Props = { const VariantZmenu = (props: Props) => { const { content } = props.payload; + const { genomeIdForUrl } = useGenomeBrowserIds(); const variantMetadata = content[0]?.metadata as | ZmenuContentVariantMetadata | undefined; - const variantId = variantMetadata?.id ?? ''; + + if (!variantMetadata) { + // something has gone wrong + return null; + } + + const variantId = buildFocusVariantId({ + regionName: variantMetadata.region_name, + start: variantMetadata.start, + variantName: variantMetadata.id + }); + + const linkToVariantInGenomeBrowser = urlFor.browser({ + genomeId: genomeIdForUrl, + focus: variantId + }); return ( - + <> + + {isEnvironment([Environment.DEVELOPMENT, Environment.INTERNAL]) && ( +
+ +
+ )} + ); }; diff --git a/src/content/app/genome-browser/services/genome-browser-service/types/zmenu.ts b/src/content/app/genome-browser/services/genome-browser-service/types/zmenu.ts index 50c2bbb541..e146244642 100644 --- a/src/content/app/genome-browser/services/genome-browser-service/types/zmenu.ts +++ b/src/content/app/genome-browser/services/genome-browser-service/types/zmenu.ts @@ -65,7 +65,9 @@ export type ZmenuContentGeneMetadata = { export type ZmenuContentVariantMetadata = { alleles: string; consequence: string; - id: string; + id: string; // just the rsID; will have to be combined with region name and start coordinate for full id + region_name: string; // needed to generate full variant id + start: number; // needed to generate full variant id position: string; // formatted as "region:start-end". NOTE: start and end coordinates have commas in them variety: string; // e.g. SNV, INS... Do we have a full list of such varieties? type: ZmenuFeatureType.VARIANT; diff --git a/src/shared/components/view-in-app/ViewInApp.tsx b/src/shared/components/view-in-app/ViewInApp.tsx index 97b1b1d5f3..2a553963ac 100644 --- a/src/shared/components/view-in-app/ViewInApp.tsx +++ b/src/shared/components/view-in-app/ViewInApp.tsx @@ -77,6 +77,7 @@ export type ViewInAppProps = { onAppClick?: AppClickHandlers; onAnyAppClick?: (appName?: AppName) => void; theme?: Theme; + className?: string; }; export const ViewInApp = (props: ViewInAppProps) => { @@ -107,7 +108,7 @@ export const ViewInApp = (props: ViewInAppProps) => { } }; - const componentClasses = classNames(styles.viewInApp, { + const componentClasses = classNames(styles.viewInApp, props.className, { [styles.viewInAppLight]: theme === 'light', [styles.viewInAppDark]: theme === 'dark' }); diff --git a/src/shared/helpers/focusObjectHelpers.ts b/src/shared/helpers/focusObjectHelpers.ts index 0954ab4ea5..1657b29340 100644 --- a/src/shared/helpers/focusObjectHelpers.ts +++ b/src/shared/helpers/focusObjectHelpers.ts @@ -83,3 +83,12 @@ export const parseFocusObjectIdFromUrl = ( export const getDisplayStableId = (focusObject: Partial) => focusObject.versioned_stable_id || focusObject.stable_id || ''; + +export const buildFocusVariantId = (params: { + regionName: string; + start: number; + variantName: string; +}) => { + const { regionName, start, variantName } = params; + return `variant:${regionName}:${start}:${variantName}`; +};