From b220175a56cff59d9942c30eafda4b8b6934b197 Mon Sep 17 00:00:00 2001 From: Andrey Azov Date: Tue, 28 May 2024 21:37:00 +0100 Subject: [PATCH] Species Selector UI updates (#1140) - Remove lozenge for species that has been disabled via the "do not use" column - Add disabled species lozenges to the top of species search results page - On species search results page, move the "Close" button to the right of the "Find/Add" button - On species search results page, if no species have been selected before and thus there are no species lozenges to show, show placeholder text instead (same as on species selector main page) - On species search results page, the "Cancel" button is replaced with the CloseButtonWithLabel component - Indented the "Find a species" label above the species search field by 20px to the right (to make it consistent with the "Find a gene" label) - Fixed the flicker that was sometimes visible when the screen changed from species selector home screen to the screen of search results. --- .../app/species-selector/SpeciesSelector.tsx | 4 +- .../GenomeSelectorBySearchQuery.module.css | 4 ++ .../GenomeSelectorBySearchQuery.tsx | 14 +++--- ...nomeSelectorBySpeciesTaxonomyId.module.css | 6 ++- .../GenomeSelectorBySpeciesTaxonomyId.tsx | 8 ++++ .../species-search-field/AddSpecies.tsx | 10 ++-- .../SpeciesSearchField.module.css | 16 ++++++- .../SpeciesSearchField.tsx | 9 +++- .../SpeciesSelectorAppBar.tsx | 10 ++-- .../SpeciesSelectorSearchResultsAppBar.tsx | 46 ++++++++++--------- .../app/species/SpeciesPage.module.css | 4 -- .../species-app-bar/SpeciesAppBar.tsx | 6 +-- .../BlastSpeciesSelector.tsx | 4 +- .../GeneSearchPanel.module.css | 4 +- .../selected-species/SelectedSpecies.test.tsx | 25 ++-------- .../selected-species/SelectedSpecies.tsx | 20 ++------ .../selected-species/SpeciesLozenge.tsx | 2 +- .../SpeciesLozenge.stories.tsx | 9 ---- 18 files changed, 98 insertions(+), 103 deletions(-) diff --git a/src/content/app/species-selector/SpeciesSelector.tsx b/src/content/app/species-selector/SpeciesSelector.tsx index b865bf386f..426844544d 100644 --- a/src/content/app/species-selector/SpeciesSelector.tsx +++ b/src/content/app/species-selector/SpeciesSelector.tsx @@ -17,7 +17,7 @@ import { Route, Routes } from 'react-router-dom'; import SpeciesSelectorAppBar from './components/species-selector-app-bar/SpeciesSelectorAppBar'; -import SpeciesSearchResultsModalAppBar from './components/species-selector-search-results-app-bar/SpeciesSelectorSearchResultsAppBar'; +import SpeciesSearchResultsAppBar from './components/species-selector-search-results-app-bar/SpeciesSelectorSearchResultsAppBar'; import SpeciesManagerAppBar from './views/species-manager/species-manager-app-bar/SpeciesManagerAppBar'; import SpeciesSelectorResultsView from './views/species-selector-results-view/SpeciesSelectorResultsView'; import SpeciesSelectorMainView from './views/species-selector-main-view/SpeciesSelectorMainView'; @@ -30,7 +30,7 @@ const SpeciesSelector = () => { const appBar = ( } /> - } /> + } /> } /> } /> diff --git a/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.module.css b/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.module.css index b00c8f254d..9237ad23d1 100644 --- a/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.module.css +++ b/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.module.css @@ -18,6 +18,10 @@ .searchFieldWrapper { grid-area: search-field; + display: grid; + grid-template-columns: repeat(2, auto); + column-gap: 30px; + align-items: center; } .resultsSummaryWrapper { diff --git a/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.tsx b/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.tsx index cb713d5f82..8d4e1a7add 100644 --- a/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.tsx +++ b/src/content/app/species-selector/components/genome-selector-by-search-query/GenomeSelectorBySearchQuery.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { useState, useEffect, useDeferredValue } from 'react'; +import { useState, useLayoutEffect, useDeferredValue } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useAppSelector } from 'src/store'; @@ -49,7 +49,7 @@ const GenomeSelectorBySearchQuery = (props: Props) => { const committedSpecies = useAppSelector(getCommittedSpecies); const [searchParams, setSearchParams] = useSearchParams(); const [searchTrigger, result] = useLazyGetSpeciesSearchResultsQuery(); - const { currentData, isLoading } = result; + const { currentData, isFetching } = result; const query = searchParams.get('query') as string; @@ -69,7 +69,8 @@ const GenomeSelectorBySearchQuery = (props: Props) => { const deferredGenomes = useDeferredValue(genomes); - useEffect(() => { + // trigger the query before the component had a chance to render + useLayoutEffect(() => { searchTrigger({ query }); }, [query]); @@ -94,7 +95,7 @@ const GenomeSelectorBySearchQuery = (props: Props) => {
0} canSubmitSearch={canSubmitSearch} @@ -143,7 +144,7 @@ const TopSection = (props: TopSectionProps) => { query={props.query} canAdd={false} onAdd={props.onGenomesAdd} - onCancel={props.onClose} + onClose={props.onClose} /> @@ -159,7 +160,7 @@ const TopSection = (props: TopSectionProps) => { query={props.query} canAdd={props.canAddGenomes} onAdd={props.onGenomesAdd} - onCancel={props.onClose} + onClose={props.onClose} />
@@ -181,6 +182,7 @@ const TopSection = (props: TopSectionProps) => { onInput={props.onSearchInput} canSubmit={props.canSubmitSearch} onSearchSubmit={props.onSearchSubmit} + onClose={props.onClose} />
diff --git a/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.module.css b/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.module.css index ba3348318f..7135bf98ed 100644 --- a/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.module.css +++ b/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.module.css @@ -15,7 +15,7 @@ grid-area: top; align-items: center; justify-self: start; - grid-template-columns: [species-image] 60px [genomes-count] auto [add-button] max-content [filter] max-content; + grid-template-columns: [species-image] 60px [genomes-count] auto [add-button] max-content [close-button] auto [filter] max-content; column-gap: var(--standard-gutter); white-space: nowrap; } @@ -41,6 +41,10 @@ grid-column: add-button; } +.closeButton { + grid-column: close-button; +} + .filterWrapper { grid-column: filter; margin-left: var(--double-standard-gutter); diff --git a/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.tsx b/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.tsx index 1d846cac11..dc01dbbfb1 100644 --- a/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.tsx +++ b/src/content/app/species-selector/components/genome-selector-by-species-taxonomy-id/GenomeSelectorBySpeciesTaxonomyId.tsx @@ -15,6 +15,7 @@ */ import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import { useAppSelector } from 'src/store'; @@ -31,6 +32,7 @@ import SpeciesSearchResultsTable from 'src/content/app/species-selector/componen import GenomesFilterField from 'src/content/app/species-selector/components/genomes-filter-field/GenomesFilterField'; import { PrimaryButton } from 'src/shared/components/button/Button'; import { CircleLoader } from 'src/shared/components/loader'; +import { CloseButtonWithLabel } from 'src/shared/components/close-button/CloseButton'; import InfoPill from 'src/shared/components/info-pill/InfoPill'; import type { SpeciesSearchMatch } from 'src/content/app/species-selector/types/speciesSearchMatch'; @@ -110,11 +112,16 @@ type TopSectionProps = Props & { const TopSection = (props: TopSectionProps) => { const { genomes, stagedGenomes, speciesImageUrl } = props; + const navigate = useNavigate(); const onSpeciesAdd = () => { props.onSpeciesAdd(stagedGenomes); }; + const onClose = () => { + navigate(-1); + }; + const selectedGenomesCount = genomes.filter( (genome) => genome.isSelected ).length; @@ -140,6 +147,7 @@ const TopSection = (props: TopSectionProps) => { > Add +
diff --git a/src/content/app/species-selector/components/species-search-field/AddSpecies.tsx b/src/content/app/species-selector/components/species-search-field/AddSpecies.tsx index 55ab0ed203..641aa9ca83 100644 --- a/src/content/app/species-selector/components/species-search-field/AddSpecies.tsx +++ b/src/content/app/species-selector/components/species-search-field/AddSpecies.tsx @@ -18,7 +18,7 @@ import classNames from 'classnames'; import ShadedInput from 'src/shared/components/input/ShadedInput'; import { PrimaryButton } from 'src/shared/components/button/Button'; -import TextButton from 'src/shared/components/text-button/TextButton'; +import { CloseButtonWithLabel } from 'src/shared/components/close-button/CloseButton'; import styles from './SpeciesSearchField.module.css'; @@ -26,15 +26,15 @@ export type Props = { query: string; canAdd: boolean; onAdd: () => void; - onCancel: () => void; + onClose: () => void; }; const AddSpecies = (props: Props) => { - const { query, canAdd, onAdd, onCancel } = props; + const { query, canAdd, onAdd, onClose } = props; return (
- + { Add - Cancel +
); diff --git a/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.module.css b/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.module.css index 2a0c1a666b..f2cb4758f1 100644 --- a/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.module.css +++ b/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.module.css @@ -5,10 +5,16 @@ 'input controls'; grid-template-columns: 486px max-content; row-gap: 10px; - column-gap: 45px; + column-gap: 30px; } -.speciesSearchField label { +.grid:has(.close) { + grid-template-areas: + 'label . .' + 'input controls close'; +} + +.label { grid-area: label; margin-left: 20px; } @@ -20,6 +26,7 @@ .controls { grid-area: controls; align-self: center; + margin-left: 15px; } .submit { @@ -31,3 +38,8 @@ align-items: center; gap: 30px; } + +.close { + grid-area: close; + align-self: center; +} diff --git a/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.tsx b/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.tsx index d29c1bb889..3a13bbcab7 100644 --- a/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.tsx +++ b/src/content/app/species-selector/components/species-search-field/SpeciesSearchField.tsx @@ -20,6 +20,7 @@ import classNames from 'classnames'; import ShadedInput from 'src/shared/components/input/ShadedInput'; import { PrimaryButton } from 'src/shared/components/button/Button'; +import { CloseButtonWithLabel } from 'src/shared/components/close-button/CloseButton'; import styles from './SpeciesSearchField.module.css'; @@ -28,10 +29,11 @@ export type Props = { onSearchSubmit: (query: string) => void | (() => void); canSubmit?: boolean; onInput?: ((event: FormEvent) => void) | (() => void); + onClose?: () => void; }; export const SpeciesSearchField = (props: Props) => { - const { query, onInput, canSubmit = true } = props; + const { query, onInput, canSubmit = true, onClose } = props; const onSubmit = (event: FormEvent) => { event.preventDefault(); @@ -40,7 +42,7 @@ export const SpeciesSearchField = (props: Props) => { return (
- + { > Find + {onClose && ( + + )} ); }; diff --git a/src/content/app/species-selector/components/species-selector-app-bar/SpeciesSelectorAppBar.tsx b/src/content/app/species-selector/components/species-selector-app-bar/SpeciesSelectorAppBar.tsx index b241ec84d1..05ca7f2e93 100644 --- a/src/content/app/species-selector/components/species-selector-app-bar/SpeciesSelectorAppBar.tsx +++ b/src/content/app/species-selector/components/species-selector-app-bar/SpeciesSelectorAppBar.tsx @@ -20,7 +20,7 @@ import { useAppSelector } from 'src/store'; import * as urlFor from 'src/shared/helpers/urlHelper'; -import { getCommittedSpecies } from 'src/content/app/species-selector/state/species-selector-general-slice/speciesSelectorGeneralSelectors'; +import { getEnabledCommittedSpecies } from 'src/content/app/species-selector/state/species-selector-general-slice/speciesSelectorGeneralSelectors'; import { getQuery as readStoredGeneQuery } from 'src/content/app/species-selector/state/species-selector-gene-search-slice/speciesSelectorGeneSearchSelectors'; import AppBar, { AppName } from 'src/shared/components/app-bar/AppBar'; @@ -38,16 +38,16 @@ import styles from './SpeciesSelectorAppBar.module.css'; export const placeholderMessage = 'Find and add your favourite species to use them across the site'; -const PlaceholderMessage = () => ( +export const PlaceholderMessage = () => (
{placeholderMessage}
); export const SpeciesSelectorAppBar = () => { - const selectedSpecies = useAppSelector(getCommittedSpecies); + const enabledCommittedSpecies = useAppSelector(getEnabledCommittedSpecies); const mainContent = - selectedSpecies.length > 0 ? ( - + enabledCommittedSpecies.length > 0 ? ( + ) : ( ); diff --git a/src/content/app/species-selector/components/species-selector-search-results-app-bar/SpeciesSelectorSearchResultsAppBar.tsx b/src/content/app/species-selector/components/species-selector-search-results-app-bar/SpeciesSelectorSearchResultsAppBar.tsx index 3969247ed5..8dbeb798b4 100644 --- a/src/content/app/species-selector/components/species-selector-search-results-app-bar/SpeciesSelectorSearchResultsAppBar.tsx +++ b/src/content/app/species-selector/components/species-selector-search-results-app-bar/SpeciesSelectorSearchResultsAppBar.tsx @@ -14,36 +14,40 @@ * limitations under the License. */ -import { useNavigate } from 'react-router-dom'; +import { useAppSelector } from 'src/store'; + +import { getEnabledCommittedSpecies } from 'src/content/app/species-selector/state/species-selector-general-slice/speciesSelectorGeneralSelectors'; import AppBar, { AppName } from 'src/shared/components/app-bar/AppBar'; import { HelpPopupButton } from 'src/shared/components/help-popup'; -import { CloseButtonWithLabel } from 'src/shared/components/close-button/CloseButton'; +import SpeciesTabsSlider from 'src/shared/components/species-tabs-slider/SpeciesTabsSlider'; +import SelectedSpecies from 'src/shared/components/selected-species/SelectedSpecies'; +import { PlaceholderMessage } from 'src/content/app/species-selector/components/species-selector-app-bar/SpeciesSelectorAppBar'; + +const SpeciesSearchResultsAppBar = () => { + const enabledCommittedSpecies = useAppSelector(getEnabledCommittedSpecies); + + const mainContent = enabledCommittedSpecies.length ? ( + + {enabledCommittedSpecies.map((species) => ( + + ))} + + ) : ( + + ); -const SpeciesSearchResultsModalAppBar = () => { return ( Species Selector} - mainContent={} + mainContent={mainContent} aside={} /> ); }; -const CloseModalView = () => { - const navigate = useNavigate(); - - const handleClick = () => { - navigate(-1); - }; - - return ( - - ); -}; - -export default SpeciesSearchResultsModalAppBar; +export default SpeciesSearchResultsAppBar; diff --git a/src/content/app/species/SpeciesPage.module.css b/src/content/app/species/SpeciesPage.module.css index f0c344595b..d4dae2c4b5 100644 --- a/src/content/app/species/SpeciesPage.module.css +++ b/src/content/app/species/SpeciesPage.module.css @@ -13,10 +13,6 @@ padding-left: 30px; } -.closeButton { - /* margin-left: var(--double-standard-gutter); */ -} - .addSpeciesButton { --add-button-icon-color: var(--color-green); --add-button-label-color: var(--color-black); diff --git a/src/content/app/species/components/species-app-bar/SpeciesAppBar.tsx b/src/content/app/species/components/species-app-bar/SpeciesAppBar.tsx index 3e77d431e7..f135ee79c7 100644 --- a/src/content/app/species/components/species-app-bar/SpeciesAppBar.tsx +++ b/src/content/app/species/components/species-app-bar/SpeciesAppBar.tsx @@ -19,7 +19,7 @@ import { useSelector } from 'react-redux'; import { AppName as AppNameText } from 'src/global/globalConfig'; import { getActiveGenomeId } from 'src/content/app/species/state/general/speciesGeneralSelectors'; -import { getCommittedSpecies } from 'src/content/app/species-selector/state/species-selector-general-slice/speciesSelectorGeneralSelectors'; +import { getEnabledCommittedSpecies } from 'src/content/app/species-selector/state/species-selector-general-slice/speciesSelectorGeneralSelectors'; import AppBar, { AppName } from 'src/shared/components/app-bar/AppBar'; import SpeciesManagerIndicator from 'src/shared/components/species-manager-indicator/SpeciesManagerIndicator'; @@ -35,9 +35,9 @@ type SpeciesAppBarProps = { const SpeciesAppBar = (props: SpeciesAppBarProps) => { const activeGenomeId = useSelector(getActiveGenomeId); - const species = useSelector(getCommittedSpecies); + const enabledCommittedSpecies = useSelector(getEnabledCommittedSpecies); - const speciesTabs = species.map((species, index) => ( + const speciesTabs = enabledCommittedSpecies.map((species, index) => ( { query={props.query} canAdd={false} onAdd={props.onGenomesAdd} - onCancel={props.onClose} + onClose={props.onClose} /> @@ -182,7 +182,7 @@ const TopSection = (props: TopSectionProps) => { query={props.query} canAdd={props.canAddGenomes} onAdd={props.onGenomesAdd} - onCancel={props.onClose} + onClose={props.onClose} />
diff --git a/src/shared/components/gene-search-panel/GeneSearchPanel.module.css b/src/shared/components/gene-search-panel/GeneSearchPanel.module.css index 43064a2e04..8c3e809915 100644 --- a/src/shared/components/gene-search-panel/GeneSearchPanel.module.css +++ b/src/shared/components/gene-search-panel/GeneSearchPanel.module.css @@ -1,5 +1,5 @@ .main { - --inner-block-offset-left: 25px; + --inner-block-offset-left: 20px; padding-bottom: var(--global-padding-bottom); padding-left: var(--global-padding-left); padding-top: 12px; @@ -24,7 +24,7 @@ .searchLabel { grid-area: label; - margin-left: 25px; + margin-left: var(--inner-block-offset-left); } .searchField { diff --git a/src/shared/components/selected-species/SelectedSpecies.test.tsx b/src/shared/components/selected-species/SelectedSpecies.test.tsx index 9bc89ee7f9..af17e2efc0 100644 --- a/src/shared/components/selected-species/SelectedSpecies.test.tsx +++ b/src/shared/components/selected-species/SelectedSpecies.test.tsx @@ -18,7 +18,6 @@ import { faker } from '@faker-js/faker'; import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import set from 'lodash/fp/set'; -import merge from 'lodash/fp/merge'; import createRootReducer from 'src/root/rootReducer'; import { Provider } from 'react-redux'; import { configureStore } from '@reduxjs/toolkit'; @@ -44,15 +43,9 @@ const minimalProps = { onClick: jest.fn() }; -const mockState = { - committedItems: [], - speciesNameDisplayOption: 'assembly-accession-id' -}; - describe('', () => { const store = configureStore({ - reducer: createRootReducer(), - preloadedState: mockState as any + reducer: createRootReducer() }); const renderSelectedSpecies = (props: SelectedSpeciesProps) => render( @@ -68,13 +61,6 @@ describe('', () => { expect(lozenge.classList.contains('themeBlack')).toBe(true); }); - it('has correct classes when active and not enabled', () => { - const props = set('species.isEnabled', false, minimalProps); - const { container } = renderSelectedSpecies(props); - const lozenge = container.firstChild as HTMLElement; - expect(lozenge.classList.contains('themeGrey')).toBe(true); - }); - it('has correct classes when inactive and enabled', () => { const props = set('isActive', false, minimalProps); const { container } = renderSelectedSpecies(props); @@ -82,14 +68,11 @@ describe('', () => { expect(lozenge.classList.contains('themeBlue')).toBe(true); }); - it('has correct classes when inactive and not enabled', () => { - const props = merge(minimalProps, { - isActive: false, - species: { isEnabled: false } - }); + it('has correct classes when disabled', () => { + const props = { ...minimalProps, disabled: true }; const { container } = renderSelectedSpecies(props); const lozenge = container.firstChild as HTMLElement; - expect(lozenge.classList.contains('themeIceBlue')).toBe(true); + expect(lozenge.classList.contains('themeGrey')).toBe(true); }); }); diff --git a/src/shared/components/selected-species/SelectedSpecies.tsx b/src/shared/components/selected-species/SelectedSpecies.tsx index fcd0c0299d..05401c792d 100644 --- a/src/shared/components/selected-species/SelectedSpecies.tsx +++ b/src/shared/components/selected-species/SelectedSpecies.tsx @@ -50,11 +50,7 @@ const SelectedSpecies = (props: Props) => { }; const getSpeciesLozengeProps = (props: Props) => { - const { - isActive = false, - species: { isEnabled }, - disabled - } = props; + const { isActive = false, disabled } = props; // TODO: add invalid (red) species when we start having them @@ -66,25 +62,15 @@ const getSpeciesLozengeProps = (props: Props) => { } as const; } - if (isActive && isEnabled) { + if (isActive) { return { theme: 'black', disabled: true, 'data-active': true } as const; - } else if (isActive && !isEnabled) { - return { - theme: 'grey', - disabled: true, - 'data-active': true - } as const; - } else if (!isActive && isEnabled) { - return { - theme: 'blue' - } as const; } else { return { - theme: 'ice-blue' + theme: 'blue' } as const; } }; diff --git a/src/shared/components/selected-species/SpeciesLozenge.tsx b/src/shared/components/selected-species/SpeciesLozenge.tsx index 67e05da059..65691fc6ff 100644 --- a/src/shared/components/selected-species/SpeciesLozenge.tsx +++ b/src/shared/components/selected-species/SpeciesLozenge.tsx @@ -33,7 +33,7 @@ import type { SpeciesNameDisplayOption } from 'src/content/app/species-selector/ import styles from './SpeciesLozenge.module.css'; -type SpeciesLozengeTheme = 'blue' | 'black' | 'ice-blue' | 'grey' | 'red'; +type SpeciesLozengeTheme = 'blue' | 'black' | 'grey' | 'red'; export type Props = DetailedHTMLProps< ButtonHTMLAttributes, diff --git a/stories/shared-components/species-lozenge/SpeciesLozenge.stories.tsx b/stories/shared-components/species-lozenge/SpeciesLozenge.stories.tsx index 220bbd2cb7..c31aa562e6 100644 --- a/stories/shared-components/species-lozenge/SpeciesLozenge.stories.tsx +++ b/stories/shared-components/species-lozenge/SpeciesLozenge.stories.tsx @@ -49,15 +49,6 @@ const SpeciesLozengeThemes = () => { black theme
-
- - ice-blue theme -
-