Unverified Commit b683a879 authored by Imran Salam's avatar Imran Salam Committed by GitHub
Browse files

Fix flashing issue in in-app search for GB (#724)

parent 6ccff56b
Pipeline #263272 passed with stages
in 4 minutes and 35 seconds
@import 'src/styles/common';
.entityViewerSidebarModal {
position: relative;
height: 100%;
overflow: auto;
h3 {
font-size: 14px;
margin: 0 0 24px 0;
}
p {
margin-bottom: 30px;
}
}
.closeButton {
position: absolute;
right: 0;
top: 0;
}
.sectionTitle {
color: $dark-grey;
font-size: 12px;
border-bottom: 1px solid $grey;
margin-bottom: 15px;
position: relative;
margin-top: 20px;
font-weight: $light;
}
......@@ -24,8 +24,6 @@ import { SidebarModalView } from 'src/content/app/entity-viewer/state/sidebar/en
import SidebarModal from 'src/shared/components/layout/sidebar-modal/SidebarModal';
import styles from './EntityViewerSidebarModal.scss';
const entityViewerSidebarModals: Record<
SidebarModalView,
LazyExoticComponent<() => JSX.Element | null>
......@@ -63,16 +61,14 @@ export const EntityViewerSidebarModal = () => {
entityViewerSidebarModalTitles[entityViewerSidebarModalView];
return (
<section className={styles.entityViewerSidebarModal}>
<Suspense fallback={<div>Loading...</div>}>
<SidebarModal
title={modalViewTitle}
onClose={() => dispatch(closeSidebarModal())}
>
{<ModalView />}
</SidebarModal>
</Suspense>
</section>
<Suspense fallback={<div>Loading...</div>}>
<SidebarModal
title={modalViewTitle}
onClose={() => dispatch(closeSidebarModal())}
>
{<ModalView />}
</SidebarModal>
</Suspense>
);
};
......
......@@ -30,7 +30,10 @@ import { closeDrawer } from 'src/content/app/genome-browser/state/drawer/drawerS
import { getBrowserNavOpenState } from 'src/content/app/genome-browser/state/browser-nav/browserNavSelectors';
import { getBrowserActiveGenomeId } from './state/browser-general/browserGeneralSelectors';
import { getIsTrackPanelOpened } from 'src/content/app/genome-browser/state/track-panel/trackPanelSelectors';
import {
getIsTrackPanelModalOpened,
getIsTrackPanelOpened
} from 'src/content/app/genome-browser/state/track-panel/trackPanelSelectors';
import { getIsDrawerOpened } from 'src/content/app/genome-browser/state/drawer/drawerSelectors';
import { getBreakpointWidth } from 'src/global/globalSelectors';
......@@ -40,6 +43,7 @@ import BrowserNavBar from './components/browser-nav/BrowserNavBar';
import TrackPanel from './components/track-panel/TrackPanel';
import TrackPanelBar from './components/track-panel/components/track-panel-bar/TrackPanelBar';
import TrackPanelTabs from './components/track-panel/components/track-panel-tabs/TrackPanelTabs';
import TrackPanelModal from './components/track-panel/components/track-panel-modal/TrackPanelModal';
import BrowserAppBar from './components/browser-app-bar/BrowserAppBar';
import Drawer from './components/drawer/Drawer';
import { StandardAppLayout } from 'src/shared/components/layout';
......@@ -54,6 +58,7 @@ export const Browser = () => {
const browserNavOpenState = useSelector(getBrowserNavOpenState);
const isDrawerOpened = useSelector(getIsDrawerOpened);
const isTrackPanelOpened = useSelector(getIsTrackPanelOpened);
const isTrackPanelModalOpened = useSelector(getIsTrackPanelModalOpened);
const viewportWidth = useSelector(getBreakpointWidth);
const { search } = useLocation(); // from document.location provided by the router
......@@ -90,13 +95,19 @@ export const Browser = () => {
</>
);
const SideBarContent = isTrackPanelModalOpened ? (
<TrackPanelModal />
) : (
<TrackPanel />
);
return (
<div className={styles.genomeBrowser}>
<BrowserAppBar onSpeciesSelect={changeGenomeId} />
{activeGenomeId && focus ? (
<StandardAppLayout
mainContent={mainContent}
sidebarContent={<TrackPanel />}
sidebarContent={SideBarContent}
sidebarNavigation={<TrackPanelTabs />}
sidebarToolstripContent={<TrackPanelBar />}
onSidebarToggle={onSidebarToggle}
......
......@@ -46,9 +46,6 @@ jest.mock('./components/track-panel-bar/TrackPanelBar', () => () => (
jest.mock('./components/track-panel-list/TrackPanelList', () => () => (
<div className="trackPanelList" />
));
jest.mock('./components/track-panel-modal/TrackPanelModal', () => () => (
<div className="trackPanelModal" />
));
jest.mock(
'src/content/app/genome-browser/components/drawer/Drawer',
() => () => <div className="drawer" />
......@@ -89,19 +86,5 @@ describe('<TrackPanel />', () => {
expect(container.querySelector('.trackPanelList')).toBeTruthy();
});
it('renders track panel modal when necessary requirements are satisfied', () => {
const activeGenomeId = mockState.browser.browserGeneral.activeGenomeId;
const { container } = renderComponent(
set(
`browser.trackPanel.${activeGenomeId}.isTrackPanelModalOpened`,
true,
mockState
)
);
expect(container.querySelector('.trackPanelModal')).toBeTruthy();
});
});
});
......@@ -18,10 +18,8 @@ import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
import TrackPanelList from './components/track-panel-list/TrackPanelList';
import TrackPanelModal from './components/track-panel-modal/TrackPanelModal';
import { SidebarLoader } from 'src/shared/components/loader';
import { getIsTrackPanelModalOpened } from 'src/content/app/genome-browser/state/track-panel/trackPanelSelectors';
import {
getBrowserActiveGenomeId,
getBrowserActiveFocusObject
......@@ -32,7 +30,6 @@ import useGenomeBrowser from 'src/content/app/genome-browser/hooks/useGenomeBrow
export const TrackPanel = () => {
const activeGenomeId = useSelector(getBrowserActiveGenomeId);
const activeFocusObject = useSelector(getBrowserActiveFocusObject);
const isTrackPanelModalOpened = useSelector(getIsTrackPanelModalOpened);
const { genomeBrowser, restoreBrowserTrackStates } = useGenomeBrowser();
......@@ -45,15 +42,7 @@ export const TrackPanel = () => {
}
}, [activeFocusObject]);
return shouldRenderContent ? (
isTrackPanelModalOpened ? (
<TrackPanelModal />
) : (
<TrackPanelList />
)
) : (
<SidebarLoader />
);
return shouldRenderContent ? <TrackPanelList /> : <SidebarLoader />;
};
export default TrackPanel;
......@@ -27,6 +27,8 @@ import { TrackPanelBar } from './TrackPanelBar';
import * as drawerActions from 'src/content/app/genome-browser/state/drawer/drawerSlice';
import * as trackPanelActions from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
import { TrackPanelModalView } from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
jest.mock(
'src/shared/components/image-button/ImageButton',
() => (props: { description: string; onClick: () => void }) =>
......@@ -49,7 +51,7 @@ const mockState = {
trackPanel: {
[fakeGenomeId]: {
isTrackPanelOpened: true,
trackPanelModalView: 'bookmarks'
trackPanelModalView: TrackPanelModalView.BOOKMARKS
}
}
}
......@@ -87,7 +89,7 @@ describe('<TrackPanelBar />', () => {
)
);
const bookmarksButton = [...container.querySelectorAll('button')].find(
(button) => button.innerHTML === 'Previously viewed'
(button) => button.innerHTML === TrackPanelModalView.BOOKMARKS
) as HTMLButtonElement;
userEvent.click(bookmarksButton);
......@@ -103,7 +105,7 @@ describe('<TrackPanelBar />', () => {
activeGenomeId: fakeGenomeId,
data: {
...mockState.browser.trackPanel[fakeGenomeId],
trackPanelModalView: 'bookmarks',
trackPanelModalView: TrackPanelModalView.BOOKMARKS,
isTrackPanelModalOpened: true
}
};
......@@ -145,7 +147,7 @@ describe('<TrackPanelBar />', () => {
it('causes track panel modal to close if a pressed button is clicked again', () => {
const { container } = renderComponent();
const bookmarksButton = [...container.querySelectorAll('button')].find(
(button) => button.innerHTML === 'Previously viewed'
(button) => button.innerHTML === TrackPanelModalView.BOOKMARKS
) as HTMLButtonElement;
userEvent.click(bookmarksButton);
......@@ -163,7 +165,7 @@ describe('<TrackPanelBar />', () => {
...mockState.browser.trackPanel[fakeGenomeId],
isTrackPanelModalOpened: false,
isTrackPanelOpened: true,
trackPanelModalView: ''
trackPanelModalView: null
}
};
......
......@@ -27,7 +27,8 @@ import { getBrowserActiveGenomeId } from 'src/content/app/genome-browser/state/b
import {
toggleTrackPanel,
closeTrackPanelModal,
openTrackPanelModal
openTrackPanelModal,
TrackPanelModalView
} from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
import { closeDrawer } from 'src/content/app/genome-browser/state/drawer/drawerSlice';
import { clearSearch } from 'src/shared/state/in-app-search/inAppSearchSlice';
......@@ -52,7 +53,7 @@ export const TrackPanelBar = () => {
const isDrawerOpened = useSelector(getIsDrawerOpened);
const dispatch = useDispatch();
const toggleModalView = (selectedItem: string) => {
const toggleModalView = (selectedItem: TrackPanelModalView) => {
if (!isTrackPanelOpened) {
dispatch(toggleTrackPanel(true));
}
......@@ -61,7 +62,7 @@ export const TrackPanelBar = () => {
dispatch(closeDrawer());
}
if (selectedItem === 'search') {
if (selectedItem === TrackPanelModalView.SEARCH) {
dispatch(
clearSearch({
app: 'genomeBrowser',
......@@ -89,42 +90,42 @@ export const TrackPanelBar = () => {
className={layoutStyles.sidebarIcon}
status={getViewIconStatus('search')}
description="Search"
onClick={() => toggleModalView('search')}
onClick={() => toggleModalView(TrackPanelModalView.SEARCH)}
image={SearchIcon}
/>
<ImageButton
className={layoutStyles.sidebarIcon}
status={Status.DISABLED}
description="Tracks manager"
onClick={() => toggleModalView('tracks-manager')}
onClick={() => toggleModalView(TrackPanelModalView.TRACKS_MANAGER)}
image={TracksManagerIcon}
/>
<ImageButton
className={layoutStyles.sidebarIcon}
status={getViewIconStatus('bookmarks')}
description="Previously viewed"
onClick={() => toggleModalView('bookmarks')}
onClick={() => toggleModalView(TrackPanelModalView.BOOKMARKS)}
image={BookmarkIcon}
/>
<ImageButton
className={layoutStyles.sidebarIcon}
status={Status.DISABLED}
description="Personal data"
onClick={() => toggleModalView('personal-data')}
onClick={() => toggleModalView(TrackPanelModalView.PERSONAL_DATA)}
image={PersonalDataIcon}
/>
<ImageButton
className={layoutStyles.sidebarIcon}
status={Status.DISABLED}
description="Share"
onClick={() => toggleModalView('share')}
onClick={() => toggleModalView(TrackPanelModalView.SHARE)}
image={ShareIcon}
/>
<ImageButton
className={layoutStyles.sidebarIcon}
status={Status.DISABLED}
description="Downloads"
onClick={() => toggleModalView('downloads')}
onClick={() => toggleModalView(TrackPanelModalView.DOWNLOADS)}
image={DownloadIcon}
/>
</>
......
......@@ -25,7 +25,9 @@ import set from 'lodash/fp/set';
import { createMockBrowserState } from 'tests/fixtures/browser';
import * as trackPanelActions from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
import { TrackPanelModal } from './TrackPanelModal';
import { TrackPanelModal, trackPanelModalTitles } from './TrackPanelModal';
import { TrackPanelModalView } from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
jest.mock('./modal-views/TrackPanelSearch', () => () => (
<div className="trackPanelSearch" />
......@@ -64,20 +66,25 @@ describe('<TrackPanelModal />', () => {
describe('rendering', () => {
it('displays track pane modal view for search', () => {
const { container } = renderComponent();
expect(container.querySelector('.trackPanelSearch')).toBeTruthy();
expect(container.querySelector('.title')?.innerHTML).toBe(
trackPanelModalTitles[TrackPanelModalView.SEARCH]
);
});
it('displays track pane modal view for downloads', () => {
const activeGenomeId = mockState.browser.browserGeneral.activeGenomeId;
it('displays track panel modal view for downloads', () => {
const { activeGenomeId } = mockState.browser.browserGeneral;
const { container } = renderComponent(
set(
`browser.trackPanel.${activeGenomeId}.trackPanelModalView`,
'downloads',
TrackPanelModalView.DOWNLOADS,
mockState
)
);
expect(container.querySelector('.trackPanelDownloads')).toBeTruthy();
expect(container.querySelector('.title')?.innerHTML).toBe(
trackPanelModalTitles[TrackPanelModalView.DOWNLOADS]
);
});
});
......
......@@ -14,58 +14,72 @@
* limitations under the License.
*/
import React from 'react';
import React, { lazy, Suspense, LazyExoticComponent } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getTrackPanelModalView } from 'src/content/app/genome-browser/state/track-panel/trackPanelSelectors';
import { closeTrackPanelModal } from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
import { closeDrawer } from 'src/content/app/genome-browser/state/drawer/drawerSlice';
import TrackPanelSearch from './modal-views/TrackPanelSearch';
import TracksManager from './modal-views/TracksManager';
import TrackPanelBookmarks from './modal-views/TrackPanelBookmarks';
import PersonalData from './modal-views/PersonalData';
import TrackPanelShare from './modal-views/TrackPanelShare';
import TrackPanelDownloads from './modal-views/TrackPanelDownloads';
import SidebarModal from 'src/shared/components/layout/sidebar-modal/SidebarModal';
import { TrackPanelModalView } from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
const trackPanelSidebarModals: Record<
string,
LazyExoticComponent<() => JSX.Element | null>
> = {
[TrackPanelModalView.SEARCH]: lazy(
() => import('./modal-views/TrackPanelSearch')
),
[TrackPanelModalView.TRACKS_MANAGER]: lazy(
() => import('./modal-views/TracksManager')
),
[TrackPanelModalView.BOOKMARKS]: lazy(
() => import('./modal-views/TrackPanelBookmarks')
),
[TrackPanelModalView.PERSONAL_DATA]: lazy(
() => import('./modal-views/PersonalData')
),
[TrackPanelModalView.SHARE]: lazy(
() => import('./modal-views/TrackPanelShare')
),
[TrackPanelModalView.DOWNLOADS]: lazy(
() => import('./modal-views/TrackPanelDownloads')
)
};
export const trackPanelModalTitles: { [key: string]: string } = {
[TrackPanelModalView.SEARCH]: 'Search',
[TrackPanelModalView.TRACKS_MANAGER]: 'Tracks manager',
[TrackPanelModalView.BOOKMARKS]: 'Previously viewed',
[TrackPanelModalView.PERSONAL_DATA]: 'Personal data',
[TrackPanelModalView.SHARE]: 'Share',
[TrackPanelModalView.DOWNLOADS]: 'Downloads'
};
export const TrackPanelModal = () => {
const trackPanelModalView = useSelector(getTrackPanelModalView);
const dispatch = useDispatch();
const getModalViewData = () => {
switch (trackPanelModalView) {
case 'search':
return { content: <TrackPanelSearch />, title: 'Search' };
case 'tracks-manager':
return { content: <TracksManager />, title: 'Tracks manager' };
case 'bookmarks':
return { content: <TrackPanelBookmarks />, title: 'Previously viewed' };
case 'personal-data':
return { content: <PersonalData />, title: 'Personal data' };
case 'share':
return { content: <TrackPanelShare />, title: 'Share' };
case 'downloads':
return { content: <TrackPanelDownloads />, title: 'Downloads' };
default:
return {
content: null,
title: ''
};
}
};
if (!trackPanelModalView) {
return null;
}
const ModalView = trackPanelSidebarModals[trackPanelModalView];
const modalViewTitle = trackPanelModalTitles[trackPanelModalView];
const onClose = () => {
dispatch(closeDrawer());
dispatch(closeTrackPanelModal());
};
const { title, content } = getModalViewData();
return (
<SidebarModal title={title} onClose={onClose}>
{content}
</SidebarModal>
<Suspense fallback={<div>Loading...</div>}>
<SidebarModal title={modalViewTitle} onClose={onClose}>
{<ModalView />}
</SidebarModal>
</Suspense>
);
};
......
......@@ -45,6 +45,15 @@ export type PreviouslyViewedObject = {
label: string | string[];
};
export enum TrackPanelModalView {
SEARCH = 'search',
TRACKS_MANAGER = 'Tracks manager',
BOOKMARKS = 'Previously viewed',
PERSONAL_DATA = 'Personal data',
SHARE = 'Share',
DOWNLOADS = 'Downlods'
}
export type PreviouslyViewedObjects = {
[genomeId: string]: PreviouslyViewedObject[];
};
......@@ -53,7 +62,7 @@ export type TrackPanelStateForGenome = Readonly<{
isTrackPanelModalOpened: boolean;
isTrackPanelOpened: boolean;
selectedTrackPanelTab: TrackSet;
trackPanelModalView: string;
trackPanelModalView: TrackPanelModalView | null;
bookmarks: PreviouslyViewedObject[];
previouslyViewedObjects: PreviouslyViewedObject[];
highlightedTrackId: string;
......@@ -69,7 +78,7 @@ export const defaultTrackPanelStateForGenome: TrackPanelStateForGenome = {
bookmarks: [],
previouslyViewedObjects: [],
selectedTrackPanelTab: TrackSet.GENOMIC,
trackPanelModalView: '',
trackPanelModalView: null,
highlightedTrackId: '',
isTrackPanelOpened: true,
collapsedTrackIds: []
......@@ -123,7 +132,7 @@ export const selectTrackPanelTab =
...getActiveTrackPanel(getState()),
selectedTrackPanelTab,
isTrackPanelModalOpened: false,
trackPanelModalView: ''
trackPanelModalView: null
};
dispatch(
......@@ -135,7 +144,9 @@ export const selectTrackPanelTab =
};
export const changeTrackPanelModalViewForGenome =
(trackPanelModalView: string): ThunkAction<void, any, null, Action<string>> =>
(
trackPanelModalView: TrackPanelModalView
): ThunkAction<void, any, null, Action<string>> =>
(dispatch, getState: () => RootState) => {
const activeGenomeId = getBrowserActiveGenomeId(getState());
......@@ -252,7 +263,9 @@ export const changeHighlightedTrackId =
};
export const openTrackPanelModal =
(trackPanelModalView: string): ThunkAction<void, any, null, Action<string>> =>
(
trackPanelModalView: TrackPanelModalView
): ThunkAction<void, any, null, Action<string>> =>
(dispatch, getState: () => RootState) => {
const state = getState();
......@@ -289,7 +302,7 @@ export const closeTrackPanelModal =
const data = {
...getActiveTrackPanel(state),
isTrackPanelModalOpened: false,
trackPanelModalView: ''
trackPanelModalView: null
};
dispatch(
......
......@@ -41,6 +41,7 @@ import { TrackSet } from 'src/content/app/genome-browser/components/track-panel/
import { Strand } from 'src/shared/types/thoas/strand';
import { LoadingState } from 'src/shared/types/loading-state';
import { BreakpointWidth } from 'src/global/globalConfig';
import { TrackPanelModalView } from 'src/content/app/genome-browser/state/track-panel/trackPanelSlice';
export const createCogTrackList = (): CogList => ({
'track:contig': faker.datatype.number(),
......@@ -256,7 +257,7 @@ export const createMockBrowserState = () => {
}
],
selectedTrackPanelTab: TrackSet.GENOMIC,
trackPanelModalView: 'search',
trackPanelModalView: TrackPanelModalView.SEARCH,
highlightedTrackId: '',
isTrackPanelOpened: true,
collapsedTrackIds: []
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment