diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 66b28014f..0bed47e7e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,13 +7,25 @@ smaht-portal Change Log ---------- +0.127.0 +======= +`PR 305: BM Browse View `_ + +* Implements UI of browse view + generalization of benchmarking layout +* Rework navbar to include new structure +* Adjustments to home page to include only two tiers +* Slight schema edits for facets and columns +* Update to SPC version 0.1.92 + + 0.126.1 ======= -`PR 313 SN Reference file columns ` +`PR 313 SN Reference file columns `_ * Add `title` and `version` to columns for ReferenceFile * Minor fix: remove Basecalling from the automated spreadsheet script + 0.126.0 ======= `PR246: feat: homepage updates `_ @@ -60,7 +72,7 @@ Change Log 0.124.1 ======= -`PR BM Register Text Fix `_ +`PR 297: BM Register Text Fix `_ * Update text in UserRegistrationModal to not refer to 2023 data release diff --git a/package-lock.json b/package-lock.json index 3873ef3a4..9b02a9213 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@gmod/tabix": "^1.5.3", "@gmod/vcf": "^5.0.6", "@hms-dbmi-bgm/react-workflow-viz": "0.1.11", - "@hms-dbmi-bgm/shared-portal-components": "github:4dn-dcic/shared-portal-components#0.1.91", + "@hms-dbmi-bgm/shared-portal-components": "github:4dn-dcic/shared-portal-components#0.1.92", "@reduxjs/toolkit": "^2.2.6", "auth0-lock": "^12.5.1", "d3": "^7.8.5", @@ -2368,8 +2368,8 @@ } }, "node_modules/@hms-dbmi-bgm/shared-portal-components": { - "version": "0.1.91", - "resolved": "git+ssh://git@github.com/4dn-dcic/shared-portal-components.git#4471b0d4602d1d302e7853252b7090030f146b6d", + "version": "0.1.92", + "resolved": "git+ssh://git@github.com/4dn-dcic/shared-portal-components.git#a35c9dc0def45dbf397e470cc9ccbc8b8b556017", "license": "MIT", "dependencies": { "@4dn-dcic/react-infinite": "github:4dn-dcic/react-infinite#1.1.9", diff --git a/package.json b/package.json index 03038da75..38c0fc2af 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@gmod/tabix": "^1.5.3", "@gmod/vcf": "^5.0.6", "@hms-dbmi-bgm/react-workflow-viz": "0.1.11", - "@hms-dbmi-bgm/shared-portal-components": "github:4dn-dcic/shared-portal-components#0.1.91", + "@hms-dbmi-bgm/shared-portal-components": "github:4dn-dcic/shared-portal-components#0.1.92", "@reduxjs/toolkit": "^2.2.6", "auth0-lock": "^12.5.1", "d3": "^7.8.5", diff --git a/pyproject.toml b/pyproject.toml index 1d630309c..7d7097988 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "encoded" -version = "0.126.1" +version = "0.127.0" description = "SMaHT Data Analysis Portal" authors = ["4DN-DCIC Team "] license = "MIT" diff --git a/src/encoded/browse.py b/src/encoded/browse.py index c103d60d1..15e159cfa 100644 --- a/src/encoded/browse.py +++ b/src/encoded/browse.py @@ -27,7 +27,9 @@ def includeme(config): DEFAULT_BROWSE_PARAM_LISTS = { "type": [DEFAULT_BROWSE_TYPE], - "additional_facet": DEFAULT_BROWSE_FACETS + "sample_summary.studies": ["Production"], + "status": ["released"], + # "additional_facet": DEFAULT_BROWSE_FACETS } @view_config(route_name='browse', request_method='GET', permission='search') @@ -55,8 +57,6 @@ def browse(context, request, search_type=DEFAULT_BROWSE_TYPE, return_generator=F detail="Redirected from " + str(request.path_info) ) - # TODO - # No real /browse specific UI yet; initially just basically copied static/components/SearchView.js to BrowseView.js. return search(context, request, search_type, return_generator, forced_type="Browse") diff --git a/src/encoded/homepage.py b/src/encoded/homepage.py index e3ae42e09..0dceca5ac 100644 --- a/src/encoded/homepage.py +++ b/src/encoded/homepage.py @@ -189,7 +189,7 @@ def home(context, request): 'date': f'{time.strftime("%Y-%m-%d %H:%M")} EST', '@graph': [ { - "title": "Tier 0: Benchmarking", + "title": "Benchmarking", "subtitle": "with all technologies", "categories": [ { @@ -237,7 +237,7 @@ def home(context, request): ] }, { - "title": "Tier 1", + "title": "Production", "subtitle": "with core + additional technologies", "categories": [ { @@ -251,21 +251,6 @@ def home(context, request): } ] }, - { - "title": "Tier 2", - "subtitle": "with core technologies", - "categories": [ - { - "title": "Primary Tissues", - "figures": [ - { "value": 0, "unit": "Donors" }, - { "value": 0, "unit": "Tissue Types" }, - { "value": 0, "unit": "Assays" }, - { "value": 0, "unit": "Files Generated" } - ] - } - ] - } ] } return response diff --git a/src/encoded/metadata.py b/src/encoded/metadata.py index 4eba39721..49cbb51d5 100644 --- a/src/encoded/metadata.py +++ b/src/encoded/metadata.py @@ -39,6 +39,7 @@ class MetadataArgs(NamedTuple): accessions: List[str] sort_param: str type_param: str + status: str include_extra_files: bool download_file_name: str header: Tuple[List[str], List[str], List[str]] @@ -250,6 +251,7 @@ def handle_metadata_arguments(context, request): accessions = post_params.get('accessions', []) type_param = post_params.get('type') sort_param = post_params.get('sort') + status = post_params.get('status') cli = post_params.get('cli', False) download_file_name = post_params.get('download_file_name') include_extra_files = post_params.get('include_extra_files', False) @@ -260,6 +262,7 @@ def handle_metadata_arguments(context, request): accessions = json.loads(post_params.get('accessions', '')) type_param = post_params.get('type') sort_param = post_params.get('sort') + status = post_params.get('status') cli = post_params.get('cli', False) download_file_name = post_params.get('download_file_name') include_extra_files = post_params.get('include_extra_files', False) @@ -277,7 +280,7 @@ def handle_metadata_arguments(context, request): # Note that this will become more complex as we add additional header types header = generate_file_download_header(download_file_name, cli=cli) tsv_mapping = TSV_MAPPING[FILE] - return MetadataArgs(accessions, sort_param, type_param, include_extra_files, download_file_name, header, + return MetadataArgs(accessions, sort_param, type_param, status, include_extra_files, download_file_name, header, tsv_mapping, cli) @@ -303,6 +306,8 @@ def peek_metadata(context, request): search_param['accession'] = args.accessions if args.sort_param: search_param['sort'] = args.sort_param + if args.status: + search_param['status'] = args.status search_param['limit'] = [1] # we don't care about results, just the facets search_param['additional_facet'] = ['file_size'] if args.include_extra_files: @@ -337,6 +342,8 @@ def metadata_tsv(context, request): search_param['accession'] = args.accessions if args.sort_param: search_param['sort'] = args.sort_param + if args.status: + search_param['status'] = args.status cli = args.cli search_iter = get_iterable_search_results(request, param_lists=search_param) diff --git a/src/encoded/schemas/file.json b/src/encoded/schemas/file.json index 9a62d20da..a6ef1fe0a 100644 --- a/src/encoded/schemas/file.json +++ b/src/encoded/schemas/file.json @@ -225,22 +225,66 @@ } }, "facets": { + "access_status": { + "title": "Access" + }, + "donors.display_title": { + "title": "Donor", + "search_type": "sayt", + "sayt_item_type": "Donor" + }, + "donors.age": { + "title": "Donor Age", + "aggregation_type": "range", + "number_step": 1, + "ranges": [ + { + "from": 18, + "to": 30 + }, + { + "from": 30, + "to": 55 + }, + { + "from": 55, + "to": 65 + }, + { + "from": 65 + } + ] + }, + "file_sets.libraries.analytes.samples.sample_sources.donor.sex": { + "title": "Donor Sex" + }, + "sample_summary.tissues": { + "title": "Tissue" + }, "file_sets.libraries.assay.display_title": { - "title": "Experimental Assay" + "title": "Experimental Assay", + "search_type": "sayt", + "sayt_item_type": "Donor" }, "file_sets.sequencing.sequencer.display_title": { "title": "Sequencing Platform" }, - "donors.display_title": { - "title": "Donor", - "default_hidden": true - }, "file_format.display_title": { "title": "Data Format" }, - "data_type": { + "data_category": { "title": "Data Category" }, + "data_type": { + "title": "Data Type" + }, + "reference_genome.display_title": { + "title": "Reference Genome" + }, + "date_created": { + "title" : "Release Date", + "aggregation_type" : "stats" + }, "sequencing_center.display_title": { "title": "Sequencing Center" }, diff --git a/src/encoded/static/components/app.js b/src/encoded/static/components/app.js index 72c685dc0..7150f2e20 100644 --- a/src/encoded/static/components/app.js +++ b/src/encoded/static/components/app.js @@ -218,8 +218,12 @@ export default class App extends React.PureComponent { '@type': itemType, display_title, title, - sequencing_center: { display_title: sequencingCenter } = {}, - data_generation_summary: { assays: [assayType] = [] } = {}, + sequencing_center: { + display_title: sequencingCenter, + } = {}, + data_generation_summary: { + assays: [assayType] = [], + } = {}, dataset, data_category: [file_type] = [], } = item; @@ -230,9 +234,12 @@ export default class App extends React.PureComponent { const prodItem = { item_id: itemID || itemUUID, item_name: display_title || title || null, - item_category: categories.length >= 1 ? categories[0] : 'Unknown', - item_category2: categories.length >= 2 ? categories[1] : 'Unknown', - item_category3: categories.length >= 3 ? categories[2] : 'Unknown', + item_category: + categories.length >= 1 ? categories[0] : 'Unknown', + item_category2: + categories.length >= 2 ? categories[1] : 'Unknown', + item_category3: + categories.length >= 3 ? categories[2] : 'Unknown', item_category4: assayType || null, item_category5: dataset || null, item_brand: sequencingCenter || null, @@ -419,9 +426,9 @@ export default class App extends React.PureComponent { // TODO: Remove this temporary alert in first official launch version in 2024 Alerts.queue({ - 'title' : '', - 'style': 'info', - 'message': ( + title: '', + style: 'info', + message: ( <>
New Features: The SMaHT Data Portal, V1 @@ -757,7 +764,7 @@ export default class App extends React.PureComponent { const dispatchDict = { href: windowHref, - context: event.state + context: event.state, }; batchDispatch(store, dispatchDict); } @@ -814,7 +821,12 @@ export default class App extends React.PureComponent { * @returns {void} */ onHashChange(event) { - store.dispatch({ type: 'SET_HREF', payload: document.querySelector('link[rel="canonical"]').getAttribute('href') }); + store.dispatch({ + type: 'SET_HREF', + payload: document + .querySelector('link[rel="canonical"]') + .getAttribute('href'), + }); } /** @@ -1150,7 +1162,11 @@ export default class App extends React.PureComponent { } reduxDispatchDict.context = response; - const payloadReduxDispatchDict = _.extend({}, reduxDispatchDict, includeReduxDispatch); + const payloadReduxDispatchDict = _.extend( + {}, + reduxDispatchDict, + includeReduxDispatch + ); batchDispatch(store, payloadReduxDispatchDict); return response; }) @@ -1778,6 +1794,7 @@ class BodyElement extends React.PureComponent { scrolledPast160: null, scrolledPast240: null, scrolledPast360: null, + scrolledPast460: null, //'scrollTop' : null // Not used, too many state updates if were to be. windowWidth: null, windowHeight: null, @@ -2088,6 +2105,7 @@ class BodyElement extends React.PureComponent { let scrolledPast160 = false; let scrolledPast240 = false; let scrolledPast360 = false; + let scrolledPast460 = false; if ( // Fixed nav takes effect at medium grid breakpoint or wider. @@ -2108,6 +2126,9 @@ class BodyElement extends React.PureComponent { if (currentScrollTop > 360) { scrolledPast360 = true; } + if (currentScrollTop > 460) { + scrolledPast460 = true; + } } return { @@ -2116,6 +2137,7 @@ class BodyElement extends React.PureComponent { scrolledPast160, scrolledPast240, scrolledPast360, + scrolledPast460, }; }); }; @@ -2175,6 +2197,7 @@ class BodyElement extends React.PureComponent { scrolledPast160, scrolledPast240, scrolledPast360, + scrolledPast460, scrolledPastTop, classList, isFullscreen, @@ -2189,6 +2212,7 @@ class BodyElement extends React.PureComponent { if (scrolledPast160) bodyClassList.push('scrolled-past-160'); if (scrolledPast240) bodyClassList.push('scrolled-past-240'); if (scrolledPast360) bodyClassList.push('scrolled-past-360'); + if (scrolledPast460) bodyClassList.push('scrolled-past-460'); if (isFullscreen) { bodyClassList.push('is-full-screen'); } else if (testWarningPresent) { @@ -2257,7 +2281,7 @@ class BodyElement extends React.PureComponent { let innerContainerMinHeight; if (mounted && windowHeight) { const rgs = responsiveGridState(windowWidth); - if ({ xxl:1, xl: 1, lg: 1, md: 1 }[rgs]) { + if ({ xxl: 1, xl: 1, lg: 1, md: 1 }[rgs]) { innerContainerMinHeight = // Hardcoded: // - minus top nav full height, footer, [testWarning] @@ -2299,9 +2323,12 @@ class BodyElement extends React.PureComponent { const tooltipGlobalEventOff = isMobileBrowser ? 'click' : undefined; + const { '@type': { 0: atType = '' } = [] } = context || {}; + return ( // We skip setting `props.dangerouslySetInnerHTML` if mounted, since this data is only used for initializing over server-side-rendered HTML. - {mounted ? + {mounted ? ( : null} + /> + ) : null} ); } diff --git a/src/encoded/static/components/browse/BrowseView.js b/src/encoded/static/components/browse/BrowseView.js index 08ce8ae84..4e0dbaa41 100644 --- a/src/encoded/static/components/browse/BrowseView.js +++ b/src/encoded/static/components/browse/BrowseView.js @@ -3,40 +3,42 @@ import React from 'react'; import memoize from 'memoize-one'; import _ from 'underscore'; -import url from 'url'; +import { OverlayTrigger, Popover } from 'react-bootstrap'; import { - memoizedUrlParse, schemaTransforms, analytics, + valueTransforms, } from '@hms-dbmi-bgm/shared-portal-components/es/components/util'; import { SearchView as CommonSearchView } from '@hms-dbmi-bgm/shared-portal-components/es/components/browse/SearchView'; -import { DetailPaneStateCache } from '@hms-dbmi-bgm/shared-portal-components/es/components/browse/components/DetailPaneStateCache'; -import { columnExtensionMap } from './columnExtensionMap'; + +import { SelectionItemCheckbox } from '@hms-dbmi-bgm/shared-portal-components/es/components/browse/components/SelectedItemsController'; +import { LocalizedTime } from '@hms-dbmi-bgm/shared-portal-components/es/components/ui/LocalizedTime'; +import { Alerts } from '@hms-dbmi-bgm/shared-portal-components/es/components/ui/Alerts'; + +import { columnExtensionMap as originalColExtMap } from './columnExtensionMap'; import { Schemas } from './../util'; import { - TitleAndSubtitleBeside, PageTitleContainer, TitleAndSubtitleUnder, pageTitleViews, EditingItemPageTitle, + OnlyTitle, } from './../PageTitleSection'; +import SlidingSidebarLayout from './../shared/SlidingSidebarLayout'; +import { + SelectAllFilesButton, + SelectedItemsDownloadButton, +} from '../static-pages/components/SelectAllAboveTableComponent'; +import { BrowseViewControllerWithSelections } from '../static-pages/components/TableControllerWithSelections'; +import { BrowseLink } from './browse-view/BrowseLink'; +import { BrowseSummaryStatController } from './browse-view/BrowseSummaryStatController'; +import { BrowseViewAboveFacetListComponent } from './browse-view/BrowseViewAboveFacetListComponent'; +import { BrowseViewAboveSearchTableControls } from './browse-view/BrowseViewAboveSearchTableControls'; export default function BrowseView(props) { - const { - context: { '@type': searchPageType = ['ItemSearchResults'] }, - } = props; - const isCaseSearch = searchPageType[0] === 'CaseSearchResults'; - - if (isCaseSearch) { - return ( - - - - ); - } - - return ; + const { session } = props; + return ; } export class BrowseViewBody extends React.PureComponent { @@ -120,42 +122,17 @@ export class BrowseViewBody extends React.PureComponent { return facets; } - /** Not currently used. */ - static filteredFilters(filters) { - const typeFilterCount = filters.reduce(function (m, { field }) { - if (field === 'type') return m + 1; - return m; - }, 0); - return filters.filter(function ({ field, term }) { - if (field === 'type') { - if (term === 'Item') { - return false; - } - if (typeFilterCount === 1) { - return false; - } - } - return true; - }); - } - constructor(props) { super(props); this.memoized = { transformedFacets: memoize(BrowseViewBody.transformedFacets), - filteredFilters: memoize(BrowseViewBody.filteredFilters), }; } render() { - const { - isCaseSearch = false, - context, - currentAction, - schemas, - } = this.props; - - // We don't need full screen btn on CGAP as already full width. + const { alerts } = this.props; + + // We don't need full screen btn on SMaHT const passProps = _.omit( this.props, 'isFullscreen', @@ -163,39 +140,344 @@ export class BrowseViewBody extends React.PureComponent { 'isCaseSearch' ); - //const filters = BrowseView.filteredFilters(context.filters || []); - const facets = this.memoized.transformedFacets( - context, - currentAction, - schemas - ); - const tableColumnClassName = 'results-column col'; - const facetColumnClassName = 'facets-column col-auto'; - return ( -
- - HELLO: THIS IS BROWSE-VIEW! +
+ +
+

+ Browse Production Data By +

+
+ + + + +
+
+
+

+ SMaHT Data Summary +

+ +
+
+ + + + + +
+
+
+ + + +
+
); } } +const BrowseViewSearchTable = (props) => { + const { + session, + context, + currentAction, + schemas, + selectedItems, + onSelectItem, + onResetSelectedItems, + } = props; + const facets = BrowseViewBody.transformedFacets( + context, + currentAction, + schemas + ); + const tableColumnClassName = 'results-column col'; + const facetColumnClassName = 'facets-column col-auto'; + + const selectedFileProps = { + selectedItems, // From SelectedItemsController + onSelectItem, // From SelectedItemsController + onResetSelectedItems, // From SelectedItemsController + }; + + const passProps = _.omit( + props, + 'isFullscreen', + 'toggleFullScreen', + 'isCaseSearch' + ); + + const aboveFacetListComponent = ; + const aboveTableComponent = ( + + }> + + + Download {selectedItems.size} Selected Files + + + ); + + /** + * A column extension map specifically for browse view file tables. + * Some of these things may be worth moving to the global colextmap eventually. + */ + const columnExtensionMap = { + ...originalColExtMap, // Pull in defaults for all tables + // Then overwrite or add onto the ones that already are there: + // Select all button + '@type': { + colTitle: ( + // Context now passed in from HeadersRowColumn (for file count) + + ), + hideTooltip: true, + noSort: true, + widthMap: { lg: 40, md: 40, sm: 40 }, + render: (result, parentProps) => { + return ( + + ); + }, + }, + // Access + access_status: { + widthMap: { lg: 60, md: 60, sm: 60 }, + colTitle: , + render: function (result, parentProps) { + const { access_status } = result || {}; + + if (access_status === 'Protected') { + return ( + + + + ); + } + return ( + {access_status} + ); + }, + }, + // File + annotated_filename: { + widthMap: { lg: 500, md: 400, sm: 300 }, + colTitle: ( + <> + File + + File nomenclature breakdown + + + ), + render: function (result, parentProps) { + const { + '@id': atId, + display_title, + annotated_filename, + } = result || {}; + + return ( + + + {annotated_filename || display_title} + + + ); + }, + }, + // Donor + donors: { + widthMap: { lg: 102, md: 102, sm: 102 }, + render: function (result, parentProps) { + const { donors: { 0: { display_title } = {} } = [] } = + result || {}; + return display_title || null; + }, + }, + // Assay + 'file_sets.libraries.assay.display_title': { + widthMap: { lg: 136, md: 136, sm: 136 }, + }, + // Tissue + 'sample_summary.tissues': {}, + // Data Category + data_category: { + render: function (result, parentProps) { + const { data_category = [] } = result || {}; + if (data_category.length === 0) { + return null; + } else if (data_category.length === 1) { + return data_category[0]; + } else { + return data_category.join(', '); + } + }, + }, + // Data Type + data_type: { + widthMap: { lg: 124, md: 124, sm: 124 }, + render: function (result, parentProps) { + const { data_type = [] } = result || {}; + if (data_type.length === 0) { + return null; + } else if (data_type.length === 1) { + return data_type[0]; + } else { + return data_type.join(', '); + } + }, + }, + // File Size + file_size: { + widthMap: { lg: 105, md: 100, sm: 100 }, + render: function (result, parentProps) { + const value = result?.file_size; + if (!value) return null; + return ( + + {valueTransforms.bytesToLargerUnit(value)} + + ); + }, + }, + // Released + date_created: { + colTitle: 'Released', + widthMap: { lg: 115, md: 115, sm: 115 }, + render: function (result, parentProps) { + const value = result?.date_created; + if (!value) return null; + return ( + + + + ); + }, + }, + // Platform + 'file_sets.sequencing.sequencer.display_title': { + widthMap: { lg: 170, md: 160, sm: 150 }, + }, + // Format + 'file_format.display_title': { + widthMap: { lg: 100, md: 90, sm: 80 }, + }, + // Software + 'software.display_title': { + widthMap: { lg: 151, md: 151, sm: 151 }, + }, + }; + + return ( + + ); +}; + const BrowseViewPageTitle = React.memo(function BrowseViewPageTitle(props) { const { context, schemas, currentAction, alerts } = props; @@ -218,25 +500,84 @@ const BrowseViewPageTitle = React.memo(function BrowseViewPageTitle(props) { ); } - const thisTypeTitle = schemaTransforms.getSchemaTypeFromSearchContext( - context, - schemas - ); - const subtitle = thisTypeTitle ? ( - - for {thisTypeTitle} - - ) : null; + const commonCls = 'col-12'; return ( - - - Search - + +
+ {/* Using static breadcrumbs here, but will likely need its own component in future */} +
+ +
+ Data + +
+
+ Browse By File +
+
+ + SMaHT Production Data + +
); }); +const TypeColumnTitlePopover = function (props) { + const { + children = [], + className, + popID, + tooltip, + placement = 'auto', + } = props || {}; + + const popover = ( + + {children} + + ); + const cls = + 'btn btn-link text-decoration-none' + + (className ? ' ' + className : ''); + return ( + + {function ({ ref, ...triggerHandlers }) { + return ( + + ); + }} + + ); +}; + pageTitleViews.register(BrowseViewPageTitle, 'Browse'); pageTitleViews.register(BrowseViewPageTitle, 'Browse', 'selection'); pageTitleViews.register(BrowseViewPageTitle, 'Browse', 'add'); diff --git a/src/encoded/static/components/browse/browse-view/BrowseLink.js b/src/encoded/static/components/browse/browse-view/BrowseLink.js new file mode 100644 index 000000000..63bd5f15d --- /dev/null +++ b/src/encoded/static/components/browse/browse-view/BrowseLink.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { BrowseLinkIcon } from './BrowseLinkIcon'; + +export const BrowseLink = React.memo(function BrowseLink(props) { + const { type, disabled } = props; + + if (disabled) { + return ( +
+ +
+ {type} + + Coming Soon + +
+
+ ); + } + + return ( + + + {type} + + ); +}); diff --git a/src/encoded/static/components/browse/browse-view/BrowseLinkIcon.js b/src/encoded/static/components/browse/browse-view/BrowseLinkIcon.js new file mode 100644 index 000000000..e0c0b64d6 --- /dev/null +++ b/src/encoded/static/components/browse/browse-view/BrowseLinkIcon.js @@ -0,0 +1,43 @@ +import React from 'react'; + +export const BrowseLinkIcon = React.memo(function BrowseLinkIcon(props) { + const { type, cls = '' } = props; + + let iconCls; + let dataAttribute; + + switch (type) { + case 'File': + iconCls = 'file'; + dataAttribute = 'file'; + break; + case 'Donor': + iconCls = 'users'; + dataAttribute = 'donor'; + break; + case 'Tissue': + iconCls = 'lungs'; + dataAttribute = 'tissue'; + break; + case 'Assay': + iconCls = 'dna'; + dataAttribute = 'assay'; + break; + case 'File Size': + iconCls = 'download'; + dataAttribute = 'file-size'; + break; + default: + throw new Error( + 'Error in BrowseLinkIcon - Must provide a valid type.' + ); + } + + return ( +
+ +
+ ); +}); diff --git a/src/encoded/static/components/browse/browse-view/BrowseSummaryStatController.js b/src/encoded/static/components/browse/browse-view/BrowseSummaryStatController.js new file mode 100644 index 000000000..2becc45e0 --- /dev/null +++ b/src/encoded/static/components/browse/browse-view/BrowseSummaryStatController.js @@ -0,0 +1,153 @@ +import React, { useState, useCallback, useEffect } from 'react'; + +import { + ajax, + valueTransforms, +} from '@hms-dbmi-bgm/shared-portal-components/es/components/util'; + +import { BrowseLinkIcon } from './BrowseLinkIcon'; + +export const BrowseSummaryStatController = (props) => { + const { type, useSearch = false, additionalSearchQueries = '' } = props; + + const [loading, setLoading] = useState(true); + const [error, setError] = useState(false); + const [value, setValue] = useState(''); + const [units, setUnits] = useState(''); + + const postData = { + type: type !== 'File Size' ? type : 'File', + status: 'released', + }; + + const callbackFxn = useCallback((resp) => { + if (!useSearch) { + resp.forEach((facet) => { + if (facet.field == 'status') { + facet.terms.forEach((term) => { + if (term.key == 'released') { + setValue(term.doc_count); + } + }); + } + }); + } else { + // Use search for File count total and File Size total + const { facets = [], total } = resp; + if (type === 'File Size') { + facets.forEach((facet) => { + if (facet.field === 'file_size') { + setValue( + valueTransforms.bytesToLargerUnit( + facet.sum, + 0, + false, + true + ) + ); + setUnits( + valueTransforms.bytesToLargerUnit( + facet.sum, + 0, + true, + false + ) + ); + } + }); + } else if (type === 'File') { + setValue(total); + } + } + setLoading(false); + setError(false); + }); + + const fallbackFxn = useCallback((resp) => { + console.log('BrowseSummaryStatController error', resp); + setLoading(false); + setError(true); + }); + + const getStatistics = useCallback(() => { + if (!loading) setLoading(true); + if (error) setError(false); + + if (!useSearch) { + // Using peek-metadata for basic item counts + ajax.load( + `/peek-metadata/`, + callbackFxn, + 'POST', + fallbackFxn, + JSON.stringify(postData) + ); + } else { + // Use search for more complicated query-based metrics + ajax.load( + `/search/?type=${postData.type}&format=json&status=released&limit=&additional_facet=file_size${additionalSearchQueries}`, + callbackFxn, + 'GET', + fallbackFxn + ); + } + }, [callbackFxn, fallbackFxn]); + + // On mount, get statistics + useEffect(() => { + getStatistics(); + }, []); + + return ; +}; + +const BrowseSummaryStat = React.memo(function BrowseSummaryStat(props) { + const { type, value, loading, units } = props; + + let subtitle; + switch (type) { + case 'File': + subtitle = 'Files Generated'; + break; + case 'Donor': + subtitle = 'Donors'; + break; + case 'Tissue': + subtitle = 'Tissues'; + break; + case 'Assay': + subtitle = 'Assays'; + break; + case 'File Size': + subtitle = 'Total File Size'; + break; + default: + throw new Error('Must provide a valid type.'); + } + + return ( +
+ +
+ {loading && ( +
+ {' '} + +
+ )} + {!loading && ( + <> +
+ {!value && value !== 0 ? '-' : value} + {units && {units}} +
+ + )} +
{subtitle}
+
+
+ ); +}); diff --git a/src/encoded/static/components/browse/browse-view/BrowseViewAboveFacetListComponent.js b/src/encoded/static/components/browse/browse-view/BrowseViewAboveFacetListComponent.js new file mode 100644 index 000000000..b528ffdff --- /dev/null +++ b/src/encoded/static/components/browse/browse-view/BrowseViewAboveFacetListComponent.js @@ -0,0 +1,22 @@ +import React from 'react'; + +/** + * Header section of the Browse Table. Passed as a child to + * EmbeddedSearchView (SPC), and recieves props from SelectedItemsController + */ +export const BrowseViewAboveFacetListComponent = (props) => { + const { context } = props; + + const totalResultCount = context?.total ?? 0; + + return ( +
+
+ + {totalResultCount} + {' '} + Results +
+
+ ); +}; diff --git a/src/encoded/static/components/browse/browse-view/BrowseViewAboveSearchTableControls.js b/src/encoded/static/components/browse/browse-view/BrowseViewAboveSearchTableControls.js new file mode 100644 index 000000000..682eeb171 --- /dev/null +++ b/src/encoded/static/components/browse/browse-view/BrowseViewAboveSearchTableControls.js @@ -0,0 +1,32 @@ +import React from 'react'; + +import { AboveTableControlsBase } from '@hms-dbmi-bgm/shared-portal-components/es/components/browse/components/above-table-controls/AboveTableControlsBase'; + +export const BrowseViewAboveSearchTableControls = React.memo( + function BrowseViewAboveSearchTableControls(props) { + const { + topLeftChildren, + children, + isFullscreen, + windowWidth, + toggleFullScreen, + sortBy, + } = props; + + return ( + + ); + } +); diff --git a/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownBigLink.js b/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownBigLink.js new file mode 100644 index 000000000..67c814fc7 --- /dev/null +++ b/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownBigLink.js @@ -0,0 +1,56 @@ +'use strict'; + +import React from 'react'; +import { console } from '@hms-dbmi-bgm/shared-portal-components/es/components/util'; + +export function BigDropdownBigLink(props) { + const { + children, + titleIcon = null, + className = null, + isActive = false, + disabled, + href, + ...passProps // Contains: `href`, `rel`, `onClick`, etc. + } = props; + + if (!children) return null; + + const textCol =
{children}
; + + let iconCol = null; + + if (typeof titleIcon === 'string') { + iconCol = ( +
+
+ +
+
+ ); + } else if (React.isValidElement(titleIcon)) { + iconCol = ( +
+ {titleIcon} +
+ ); + } + + return ( + +
+ {iconCol} + {textCol} +
+
+ ); +} diff --git a/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownPageTreeMenu.js b/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownPageTreeMenu.js index 83e287a3b..e23d1cecb 100644 --- a/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownPageTreeMenu.js +++ b/src/encoded/static/components/navigation/components/BigDropdown/BigDropdownPageTreeMenu.js @@ -10,6 +10,7 @@ import { memoizedUrlParse, } from '@hms-dbmi-bgm/shared-portal-components/es/components/util'; import { BigDropdownIntroductionWrapper } from './BigDropdownIntroductionWrapper'; +import { BigDropdownBigLink } from './BigDropdownBigLink'; export function BigDropdownPageTreeMenuIntroduction(props) { const { @@ -228,116 +229,110 @@ function CustomStaticLinks({ pathName, href }) { switch (pathName) { case 'data': return ( - <> -
-
-
- Benchmarking Data -
-
-
- -
-
-
- Benchmarking Tissues -
-
-
- - Donor ST001 - - - Donor ST002 - - - Donor ST003 - - - Donor ST004 - +
+
+

+ Production Data +

+
+ +

Browse By File

+
+ +

+ Browse By Donor + + {' '} + - Coming Soon + +

+
+ +

+ Browse By Tissue + + {' '} + - Coming Soon + +

+
+ +

+ Browse By Assay + + {' '} + - Coming Soon + +

+
+
+
+

+ Benchmarking Data +

+
+ + {`Cell
+ } + className="primary-big-link"> +

Cell Lines

+
+ COLO829 - Hap Map - iPSC & Fibroblasts
-
-
-
-
-
- Benchmarking Analysis + + +

Tissue Homogenates

+
+ Donor: ST001, ST002, ST003, ST004
-
-
-
-
-
- SMaHT Challenges -
-
- - + } + className="primary-big-link bottom-edge-child"> +

+ Truthset & Benchmarking Analysis +

+
+ COLO829 SNV/Indel Detection Challenge
-
+
- +
); default: return null; diff --git a/src/encoded/static/components/shared/SlidingSidebarLayout.js b/src/encoded/static/components/shared/SlidingSidebarLayout.js new file mode 100644 index 000000000..77ce6a0eb --- /dev/null +++ b/src/encoded/static/components/shared/SlidingSidebarLayout.js @@ -0,0 +1,46 @@ +import React, { useState } from 'react'; + +const SlidingSidebarLayout = (props) => { + const { children, openByDefault = true } = props; + + const [showNav, setShowNav] = useState(openByDefault); + + const childrenArray = React.Children.toArray(children); + + // Default to empty if no nav is passed + const nav = childrenArray[0] || null; + const body = childrenArray[1] || null; + + return ( +
+ {nav && ( +
+
+ + {nav} +
+
+ )} +
+ {body} +
+
+ ); +}; + +export default SlidingSidebarLayout; diff --git a/src/encoded/static/components/static-pages/components/TableControllerWithSelections.js b/src/encoded/static/components/static-pages/components/TableControllerWithSelections.js index 53e53057f..d1d90081d 100644 --- a/src/encoded/static/components/static-pages/components/TableControllerWithSelections.js +++ b/src/encoded/static/components/static-pages/components/TableControllerWithSelections.js @@ -40,3 +40,30 @@ export const TableControllerWithSelections = (props) => { ); }; + +export const BrowseViewControllerWithSelections = (props) => { + // Mostly serves as an intermediary/wrapper HOC to make selectedItemsController methods + // and props available in child table's aboveTableComponent + const { schemas, facets, session, href, context } = props; + + // Inject necessary props + const renderChildren = () => { + return React.Children.map(props.children, (child) => { + return React.cloneElement(child, { + session, + schemas, + href, + context, + facets, + }); + }); + }; + + return ( + + {renderChildren()} + + ); +}; diff --git a/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingDataMap.js b/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingDataMap.js index e927e021c..1601c2a59 100644 --- a/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingDataMap.js +++ b/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingDataMap.js @@ -95,6 +95,14 @@ export const BenchmarkingDataMap = { 'sequencing_center.display_title', 'software.display_title', 'tags', + // File facets used in production browse ui + 'access_status', + 'donors.display_title', + 'donors.age', + 'donors.sex', + 'sample_summary.tissues', + 'reference_genome.display_title', + 'date_created', ], columns: { '@type': {}, diff --git a/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingNav.js b/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingNav.js index a088e0dfb..4f193fff7 100644 --- a/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingNav.js +++ b/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingNav.js @@ -62,19 +62,7 @@ export const BenchmarkingUINav = (props) => { }); return ( -
- + <>
Cell Line Data @@ -104,7 +92,7 @@ export const BenchmarkingUINav = (props) => { />
-
+ ); }; @@ -231,7 +219,9 @@ const BenchmarkingUINavLink = (props) => { className={`sidenav-link ${isActive ? 'active' : ''} ${ isTop ? 'top' : '' } ${cls}`}> - {title} + + {title} + ); }; diff --git a/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingTable.js b/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingTable.js index 59a0c5364..f33446c01 100644 --- a/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingTable.js +++ b/src/encoded/static/components/static-pages/components/benchmarking/BenchmarkingTable.js @@ -49,7 +49,7 @@ export const BenchmarkingTable = (props) => { }; /** - * A column extension map speifically for benchmarking tables. + * A column extension map specifically for benchmarking tables. * Some of these things may be worth moving to the global colextmap eventually. */ const benchmarkingColExtMap = { @@ -90,7 +90,9 @@ export const BenchmarkingTable = (props) => { ); } - return {access_status}; + return ( + {access_status} + ); }, }, // File @@ -217,8 +219,6 @@ export const BenchmarkingTable = (props) => { }, }; - console.log('tabMap', tabMap); - return ( { 'status', 'validation_errors.name', 'version', + // File facets used in production browse ui + 'access_status', + 'donors.display_title', + 'donors.age', + 'donors.sex', + 'sample_summary.tissues', + 'reference_genome.display_title', + 'date_created', ] } hideColumns={['display_title']} diff --git a/src/encoded/static/components/static-pages/components/benchmarking/index.js b/src/encoded/static/components/static-pages/components/benchmarking/index.js index edb6ea962..18bd6c116 100644 --- a/src/encoded/static/components/static-pages/components/benchmarking/index.js +++ b/src/encoded/static/components/static-pages/components/benchmarking/index.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { BenchmarkingLayout, HashBasedTabController } from './BenchmarkingUI'; import { BenchmarkingDataMap } from './BenchmarkingDataMap'; import { BenchmarkingUINav } from './BenchmarkingNav'; +import SlidingSidebarLayout from '../../../shared/SlidingSidebarLayout'; /** * In order to be used in static sections, the following componentes MUST be imported @@ -15,18 +16,10 @@ export const BenchmarkingUI = (props) => { // Note: each child needs to be passed schemas, session, facets, href, and context return ( -
-
- -
-
- {children} -
-
+ + + <>{children} + ); }; diff --git a/src/encoded/static/components/static-pages/components/challenges/ChallengeTables.js b/src/encoded/static/components/static-pages/components/challenges/ChallengeTables.js index 9eaa4afd8..78a6082a0 100644 --- a/src/encoded/static/components/static-pages/components/challenges/ChallengeTables.js +++ b/src/encoded/static/components/static-pages/components/challenges/ChallengeTables.js @@ -41,7 +41,7 @@ const ChallengeTable = (props) => { }; /** - * A column extension map speifically for benchmarking tables. + * A column extension map specifically for challenge tables. * Some of these things may be worth moving to the global colextmap eventually. */ const benchmarkingColExtMap = { diff --git a/src/encoded/static/components/viz/HomepageFigure/AssaysCard/index.js b/src/encoded/static/components/viz/HomepageFigure/AssaysCard/index.js index 54fa82b1a..2aa51305d 100644 --- a/src/encoded/static/components/viz/HomepageFigure/AssaysCard/index.js +++ b/src/encoded/static/components/viz/HomepageFigure/AssaysCard/index.js @@ -51,14 +51,12 @@ export const AssaysCard = ({ currentTier }) => { title: 'Illumina NovaSeq', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '', title: 'Ultima Genomics', tier_0: true, tier_1: true, - tier_2: true, }, ], }, @@ -71,14 +69,12 @@ export const AssaysCard = ({ currentTier }) => { title: 'PacBio HiFi', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '', title: 'ONT', tier_0: true, tier_1: true, - tier_2: true, }, ], }, @@ -91,14 +87,12 @@ export const AssaysCard = ({ currentTier }) => { title: 'Illumina NovaSeq', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '', title: 'MAS-Seq', tier_0: true, tier_1: true, - tier_2: false, }, ], }, @@ -111,28 +105,24 @@ export const AssaysCard = ({ currentTier }) => { title: 'DLP+', tier_0: true, tier_1: true, - tier_2: false, }, { iconSrc: '', title: 'MALBAC', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'PTA and PTA-HAT-Seq', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'Cas9-targeted seq', tier_0: true, tier_1: false, - tier_2: false, }, ], }, @@ -145,21 +135,18 @@ export const AssaysCard = ({ currentTier }) => { title: 'snRNA-Seq', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'STORM-Seq', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'Tranquil-Seq', tier_0: true, tier_1: false, - tier_2: false, }, ], }, @@ -172,35 +159,30 @@ export const AssaysCard = ({ currentTier }) => { title: 'Nanoseq', tier_0: true, tier_1: true, - tier_2: false, }, { iconSrc: '', title: 'CODEC', tier_0: true, tier_1: true, - tier_2: false, }, { iconSrc: '', title: 'Duplex sequencing', tier_0: true, tier_1: true, - tier_2: false, }, { iconSrc: '', title: 'HiDEF-Seq', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'CompDuplex-Seq', tier_0: true, tier_1: false, - tier_2: false, }, ], }, @@ -213,35 +195,30 @@ export const AssaysCard = ({ currentTier }) => { title: 'NT-Seq', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'Fiber-Seq', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '', title: 'Hi-C', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '', title: 'GoTchA', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '', title: 'ATAC-Seq/MetaCS', tier_0: true, tier_1: false, - tier_2: false, }, ], }, diff --git a/src/encoded/static/components/viz/HomepageFigure/CLTCard/index.js b/src/encoded/static/components/viz/HomepageFigure/CLTCard/index.js index b816f3f12..e027b1c63 100644 --- a/src/encoded/static/components/viz/HomepageFigure/CLTCard/index.js +++ b/src/encoded/static/components/viz/HomepageFigure/CLTCard/index.js @@ -27,9 +27,7 @@ const CLTList = ({ list }) => { {item.title} - - {item.data} - + {item.data} }>
@@ -71,7 +69,6 @@ export const CLTCard = ({ currentTier }) => { title: 'Brain: unrelated donors', tier_0: true, tier_1: false, - tier_2: false, // TODO: Discuss implications adjusting overall popover style override for // max-width in _bootstrap-theme-overrides.scss (potential effect on consortium map?) data: ( @@ -92,7 +89,6 @@ export const CLTCard = ({ currentTier }) => { title: 'Brain: 4 subregions', tier_0: false, tier_1: true, - tier_2: true, // TODO: Does this also require the same note as above? }, { @@ -100,7 +96,6 @@ export const CLTCard = ({ currentTier }) => { title: 'Sun-exposed skin', tier_0: true, tier_1: true, - tier_2: true, }, { // TODO: Double check that it was correct to remove this from just Tier 0 @@ -108,14 +103,12 @@ export const CLTCard = ({ currentTier }) => { title: 'Non-exposed skin', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Adrenal Gland.svg', title: 'Adrenal medulla', tier_0: false, tier_1: true, - tier_2: true, }, ], }, @@ -127,28 +120,24 @@ export const CLTCard = ({ currentTier }) => { title: 'Heart', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Blood.svg', title: 'Blood', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Skeletal Muscle.svg', title: 'Skeletal Muscle', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Aorta.svg', title: 'Aorta', tier_0: false, tier_1: true, - tier_2: true, }, ], }, @@ -160,28 +149,24 @@ export const CLTCard = ({ currentTier }) => { title: 'Liver', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Lung.svg', title: 'Lung', tier_0: true, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Colon.svg', title: 'Colon', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '/static/img/anatomy-icons/Ascending Colon.svg', title: 'Ascending Colon', tier_0: false, tier_1: true, - tier_2: true, }, { // TODO: Double check it was correct to remove this from just tier 0 @@ -189,14 +174,12 @@ export const CLTCard = ({ currentTier }) => { title: 'Descending Colon', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Esophagus.svg', title: 'Esophagus', tier_0: false, tier_1: true, - tier_2: true, }, ], }, @@ -208,28 +191,24 @@ export const CLTCard = ({ currentTier }) => { title: 'COLO829 Mixture', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '/static/img/anatomy-icons/Cell Line Mixture.svg', title: 'HapMap Mixture', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '/static/img/anatomy-icons/Cell Line Mixture.svg', title: 'iPSC & Fibroblast', tier_0: true, tier_1: false, - tier_2: false, }, { iconSrc: '/static/img/anatomy-icons/Cell Line Mixture.svg', title: 'Descending Colon', tier_0: false, tier_1: false, - tier_2: false, }, ], }, @@ -241,21 +220,18 @@ export const CLTCard = ({ currentTier }) => { title: 'Buccal Swab', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Fibroblast.svg', title: 'Skin Fibroblast', tier_0: false, tier_1: true, - tier_2: true, }, { iconSrc: '/static/img/anatomy-icons/Testes or Ovary.svg', title: 'Testis / Ovary', tier_0: false, tier_1: true, - tier_2: true, }, ], }, diff --git a/src/encoded/static/components/viz/HomepageFigure/index.js b/src/encoded/static/components/viz/HomepageFigure/index.js index 300d6434c..96a13645b 100644 --- a/src/encoded/static/components/viz/HomepageFigure/index.js +++ b/src/encoded/static/components/viz/HomepageFigure/index.js @@ -19,17 +19,12 @@ const TierSelector = ({ currentTier, setCurrentTier }) => { -
); diff --git a/src/encoded/static/components/viz/SMaHTTimeline.js b/src/encoded/static/components/viz/SMaHTTimeline.js index 4ff8daef6..d0f5353f7 100644 --- a/src/encoded/static/components/viz/SMaHTTimeline.js +++ b/src/encoded/static/components/viz/SMaHTTimeline.js @@ -42,11 +42,12 @@ const TimelineItem = ({
- + {categories.map((category, j) => { return ( callback && callback(eventKey) ); - const isCurrentEventKey = activeEventKey === eventKey; + const isCurrentEventKey = activeEventKey.includes(eventKey.toString()); const openStatusIconCls = isCurrentEventKey ? 'icon icon-minus fas' @@ -134,7 +135,9 @@ function TimelineAccordion(props) { const { defaultActiveKey, children, activeKey } = props; return ( - {children} + + {children} + ); } @@ -216,7 +219,7 @@ const TimelineCardContent = ({ values, isError }) => { const loadStateData = { timeline_content: [ { - title: 'Tier 0: Benchmarking', + title: 'Benchmarking', subtitle: 'with all technologies', categories: [ { @@ -234,15 +237,10 @@ const loadStateData = { ], }, { - title: 'Tier 1', + title: 'Production', subtitle: 'with core + additional technologies', categories: [{ title: 'Primary Tissues' }], }, - { - title: 'Tier 2', - subtitle: 'with core technologies', - categories: [{ title: 'Primary Tissues' }], - }, ], }; diff --git a/src/encoded/static/img/Browse by file - file name breakdown.png b/src/encoded/static/img/Browse by file - file name breakdown.png new file mode 100644 index 000000000..a208ac1c0 Binary files /dev/null and b/src/encoded/static/img/Browse by file - file name breakdown.png differ diff --git a/src/encoded/static/img/misc-icons/Analysis Bench.svg b/src/encoded/static/img/misc-icons/Analysis Bench.svg new file mode 100644 index 000000000..77fd8b5e7 --- /dev/null +++ b/src/encoded/static/img/misc-icons/Analysis Bench.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/encoded/static/img/misc-icons/Cell Line bench.svg b/src/encoded/static/img/misc-icons/Cell Line bench.svg new file mode 100644 index 000000000..a4c6847be --- /dev/null +++ b/src/encoded/static/img/misc-icons/Cell Line bench.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/encoded/static/scss/encoded/_layout.scss b/src/encoded/static/scss/encoded/_layout.scss index 0b7b3d0bb..fdd8b8942 100644 --- a/src/encoded/static/scss/encoded/_layout.scss +++ b/src/encoded/static/scss/encoded/_layout.scss @@ -207,6 +207,19 @@ body.is-full-screen { HEADER & TOP AREAS (Navbar, Page Titles, etc.) ************************************************************/ +/*** +Styling of page title container for static pages, user profiles, +**/ +body[data-pathname^="/browse"]:not([data-current-action="add"]):not([data-current-action="edit"]):not([data-at-type*="Error"]) #page-title-container, +body.is-item-view[data-pathname^="/users/"]:not([data-at-type*='Error']) #page-title-container, +body:not([data-at-type*='Error']) #page-title-container.static-page-title { + background: $ss-title-background; + background-size: cover; + border: 1px solid #E7F0F3; + border-left: none; + border-right: none; +} + #page-title-container { h1.page-title { @@ -271,6 +284,104 @@ body.is-full-screen { } } +/** +Layout +*/ +.sliding-sidebar-ui-container { + // Header and description text + .sliding-sidebar-layout-container { + width: 100%; + } + + // Side nav + .sliding-sidebar-nav-container { + display: none; + } + + @include media-breakpoint-up(lg) { + display: flex; + flex: 1; + padding: 0px; + + // Header and description text + .sliding-sidebar-layout-container { + flex: 1; + padding: 20px 32px 20px 20px; + overflow: scroll; + } + + // Side nav + .sliding-sidebar-nav-container { + display: flex; + min-height: calc(100vh - 236px); + padding: 0; + + .sliding-sidebar-nav { + width: 100%; + position: relative; + padding: 25px 0px 0px 0px; + + .toggle-button { + position: absolute; + display: flex; + justify-content: center; + border-radius: 50%; + border: 1px solid #DEE2E6; + width: 26px; + height: 26px; + right: -13px; + z-index: 2; + background-color: #FCFDFF; + color: #343741; + + i { + font-size: 0.75rem; + margin: auto; + } + + &:hover { + background-color: #F6F6F6; + } + + &:active { + background-color: #f2f2f2; + } + } + } + } + &.show-nav { + padding-left: 32px; + .sliding-sidebar-nav-container{ + width: 20%; + max-width: 275px; + border-right: 1px solid #dee2e6; + transition: width 100ms ease-in-out; + } + .sliding-sidebar-layout-container { + width: 80%; + } + } + &.collapse-nav { + flex-wrap: nowrap; + .sliding-sidebar-nav-container { + width: 32px; + border-right: 1px solid #E7F0F3; + background-color: #FBFBFC; + + .sliding-sidebar-nav { + width: 100%; + :not(.toggle-button):not(.toggle-button i) { + display: none; + } + } + hr { + display: none; + } + } + } + } +} + /* ********************************************************* FOOTER diff --git a/src/encoded/static/scss/encoded/modules/_navbar.scss b/src/encoded/static/scss/encoded/modules/_navbar.scss index c39843136..a096f7a93 100644 --- a/src/encoded/static/scss/encoded/modules/_navbar.scss +++ b/src/encoded/static/scss/encoded/modules/_navbar.scss @@ -931,16 +931,41 @@ body[data-current-action="multiselect"] { // Same size, similar styling as intro-section a.big-link { + height: 83px; + @include media-breakpoint-down(sm) { + min-height: 83px; + &:not(.is-fa-icon) { + height: unset; + } + &.is-fa-icon { + height: 83px; + } + } color: inherit; position: relative; - &:hover { - color: #5d8a8e; + &:hover:not([data-disabled="true"]) { + img { + filter: brightness(0) saturate(100%) invert(58%) sepia(15%) saturate(6456%) hue-rotate(179deg) brightness(106%) contrast(101%); + } + color: #2DB3FF; text-shadow: 0 0 0; text-decoration: none; &:after { opacity: 1; } } + &[data-disabled="true"] { + color: #aaa; + > div > div > h3, + > div > div > h5, + > div > div > h4 { + color: #aaa; + } + cursor: default; + &:after { + opacity: 0 !important; + } + } > div, > div > div, > div > div > h3, @@ -955,7 +980,7 @@ body[data-current-action="multiselect"] { display: inline-block; @include after-big-link-append; } - &:hover, + &:hover:not([data-disabled="true"]), &.active { > div > div > h3, > div > div > h5, @@ -972,6 +997,12 @@ body[data-current-action="multiselect"] { font-weight: 600; } } + + img.big-link-icon-svg { + width: 40px; + filter: brightness(0) saturate(100%) invert(80%) sepia(0%) saturate(1720%) hue-rotate(168deg) brightness(105%) contrast(107%); + } + } .intro-section { @@ -1006,6 +1037,15 @@ body[data-current-action="multiselect"] { } > .tree-menu-container { + + .custom-static-links { + @include media-breakpoint-down(md) { + gap: 20px; + } + @include media-breakpoint-up(md) { + gap: 10%; + } + } > .help-menu-tree { @@ -1126,12 +1166,10 @@ body[data-current-action="multiselect"] { .big-link { .icon-beside-column { width: 75px; - margin-left: -75px; opacity: 1; transition: opacity .5s ease-out; } } - } } } diff --git a/src/encoded/static/scss/encoded/modules/_search.scss b/src/encoded/static/scss/encoded/modules/_search.scss index ba8541492..0a8330281 100644 --- a/src/encoded/static/scss/encoded/modules/_search.scss +++ b/src/encoded/static/scss/encoded/modules/_search.scss @@ -41,23 +41,38 @@ $facetlist-excluding: #450000; &[data-field="access_status"], &[data-field="annotation_filename"], &[data-field="data_type"], + &[data-field="data_category"], &[data-field="file_sets.assay.display_title"], &[data-field="file_sets.sequencing.sequencer.display_title"], + &[data-field="file_sets.libraries.assay.display_title"], &[data-field="file_format.display_title"], &[data-field="software.name"], + &[data-field="software.display_title"], + &[data-field="sample_summary.tissues"], + &[data-field="donors"], &[data-field="submission_centers.display_title"] { + // embedded search tables > .inner, > span.value { text-align: left !important; } + // browse view + >.inner>span.value { + text-align: left !important; + } } &[data-field="file_size"], &[data-field="date_created"] { + // embedded search tables > .inner, > span.value { text-align: right !important; } + // browse view + >.inner>span.value { + text-align: right !important; + } } } @@ -251,6 +266,12 @@ $facetlist-excluding: #450000; /** Btn vertical alignment (probably temporary) **/ +.above-facets-table-row { + min-height: 41px; // needs to match $search-results-result-row-height in search-view-table.scss in SPC + padding-bottom: 5px; // needs to match $search-results-above-results-row-bottom-padding in search-view-table.scss in SPC + margin-top: 7px; +} + .above-results-table-row { margin-top: 5px; @@ -326,8 +347,11 @@ body[data-pathname="/search/"]:not([data-current-action="add"]) { border-color: $search-header-icon-color; } - &[data-first-visible-column] { - padding-left: 16px; + &[data-first-visible-column]{ + padding-left: 0px; + &[data-field="@type"] { + padding-left: 16px; + } } .inner > .column-title { @@ -658,6 +682,26 @@ body[data-pathname="/search/"]:not([data-current-action="add"]) { } .search-results-outer-container { + .search-results-container .search-result-row + { + &.is-draggable > .columns.result-table-row[draggable="true"]:hover { + box-shadow: none; + } + + &.detail-closed >.columns.result-table-row>.search-result-column-block { + + &[data-first-visible-column=true]{ + padding-left: 0px; + &[data-field="@type"] { + padding-left: 16px !important; + } + } + + >.inner>.toggle-detail-button-container { + display: none; + } + } + } .search-headers-row { position: sticky; @@ -717,3 +761,217 @@ body[data-pathname="/search/"]:not([data-current-action="add"]) { } } } + +/** +* Browse View +**/ + +h2.browse-summary-header { + font-size: 1.5rem; + color: #343741; + font-weight: 600; +} + +// Popover used in File column title +#type-title-popover { + min-width: 525px; + width: 525px; + + .popover-body > img { + width: 500px; + } + + @include media-breakpoint-down(sm) { + min-width: 375px; + width: 375px; + + .popover-body > img { + width: 350px; + } + } +} + +div.browse-body { + .search-page-container { + .search-view-controls-and-results { + .facets-column .facets-container .facets-body .facet-list .search-selection-menu.dropdown > .dropdown-toggle { + font-size: .813rem; + } + + .results-column .above-results-table-row .search-result-config-panel .column-option .checkbox { + border-radius: 4px; + &.is-active { + background-color: #ebf6ff; + border-color: #5f99cf; + } + } + } + + .search-results-outer-container .search-results-container .search-result-row.detail-closed > .columns.result-table-row > .search-result-column-block[data-first-visible-column="true"][data-field="@type"], + .search-headers-row > .headers-columns-overflow-container > .columns > .search-headers-column-block[data-first-visible-column][data-field="@type"] { + padding-left: 5px !important; + } + .search-headers-row > .headers-columns-overflow-container > .columns > .search-headers-column-block[data-field="annotated_filename"] .filename-popover-color { + color: #657B95; + &:hover { + color: darken(#657B95, 15%); + } + } + } + + + @include media-breakpoint-down(lg) { + padding-top: 1rem; + padding-bottom: 1rem; + } + + @include media-breakpoint-between(md,lg) { + padding-left: 2.9rem; + padding-right: 2.9rem; + } + + @include media-breakpoint-down(md) { + padding-left: 2rem; + padding-right: 2rem; + } +} + +div.browse-summary { + background-color: #F9FCFF; + border: 1px solid #70A3E2; + border-radius: 15px; + padding: 1.25rem; + row-gap: 20px; + + div.browse-summary-stat { + height: 62px; + + @media screen and (max-width: 1020px) { + padding-left: 30px; + } + + &:not(:last-of-type) { + padding-right: 30px; + border-right: 1px solid #c0dbfb; + } + + &:not(:first-of-type) { + padding-left: 30px; + } + + > div { + div.browse-summary-stat-value { + line-height: 1.2; + font-size: 2rem; + font-weight: 600; + > span { + font-size: 1.5rem; + } + } + + div.browse-summary-stat-subtitle { + color: #657B95; + font-weight: 500; + font-size: 0.875rem; + } + } + } +} + +h3.browse-links-header, +div.browse-links { + margin-left: 10px; + margin-right: 20px; +} + +h3.browse-links-header { + font-size: 0.9rem; + font-weight: 600; + margin-bottom: 20px; +} + +div.browse-links { + display: flex; + flex-direction: column; + gap: 30px; + div.browse-link, + a.browse-link { + display: flex; + align-items: center; + gap: 10px; + font-size: 1.125rem; + color: #343741; + font-weight: 600; + >div>span { + font-size: 0.7rem; + font-weight: 400; + } + } +} + +div.browse-link-icon { + display: flex; + justify-content: center; + align-items: center; + width: 45px; + height: 45px; + border-radius: 22.5px; + + &.browse-summary-stat-icon-smaller { + font-size: 1.2em; + } + + &[data-icon-type='file'] { + background-color: #DDF1FF; + border: 1px solid #6DAAD5; + > i { + color: #0D74BD; + } + } + &[data-icon-type='donor'] { + background-color: #FBE8E8; + border: 1px solid #CC8B8B; + > i { + color: #B10808; + } + } + &[data-icon-type='tissue'] { + background-color: #D6F7EB; + border: 1px solid #5FBD8D; + > i { + color: #09AE5E; + } + } + &[data-icon-type='assay'] { + background-color: #E7E6FF; + border: 1px solid #775FBD; + > i { + color: #6A28AF; + } + } + &[data-icon-type='file-size'] { + background-color: #FFEFDB; + border: 1px solid #F47F6B; + > i { + color: #CC5D4A; + } + } +} + +/** FIX FOR BROWSE VIEW SEARCH TABLE WEIRDNESS **/ +// Overriding SPC _search.scss here because our browse view has more content before the table +// this override prevents the arrows from behaving super strangely and appearing higher up on the page +body.scrolled-past-80[data-path^="/browse"] .search-results-outer-container .search-results-container .shadow-border-layer.fixed-position-arrows > .edge-scroll-button > i.icon { + position: absolute; + margin-top: 0px; + top: unset; +} +body.scrolled-past-top[data-path^="/browse"] .search-results-outer-container .search-results-container .shadow-border-layer > .edge-scroll-button > i.icon { + margin-top: 0; + top: unset; +} +body.scrolled-past-80.scrolled-past-460[data-path^="/browse"] .search-results-outer-container .search-results-container .shadow-border-layer > .edge-scroll-button > i.icon { + position: fixed; + margin-top: 5px; + top: 50%; +} \ No newline at end of file diff --git a/src/encoded/static/scss/encoded/modules/_static-pages.scss b/src/encoded/static/scss/encoded/modules/_static-pages.scss index 7e84a7745..6ae79a686 100644 --- a/src/encoded/static/scss/encoded/modules/_static-pages.scss +++ b/src/encoded/static/scss/encoded/modules/_static-pages.scss @@ -2374,19 +2374,6 @@ div#popover-consortium-data-alluvial-table { } } -/*** -Unique styling of page title container for static pages -(also used for user profiles) -**/ -body.is-item-view[data-pathname^="/users/"] #page-title-container, -#page-title-container.static-page-title { - background: $ss-title-background; - background-size: cover; - border: 1px solid #E7F0F3; - border-left: none; - border-right: none; -} - body[data-pathname^="/data"] { .search-result-row.detail-closed >.columns.result-table-row>.search-result-column-block { &[data-first-visible-column=true] { @@ -2402,8 +2389,8 @@ body[data-pathname^="/data"] { /*** Unique styling for benchmarking pages **/ -body[data-pathname^="/data/benchmarking"] { - #post-navbar-container>#content.container:not(.error-page) { +body[data-pathname^="/data/benchmarking"]:not([data-at-type*="Error"]) { + #post-navbar-container>#content.container:not(.error-page):not(.error-boundary) { width: 100%; max-width: calc(100% - 4em); margin: 0 2em; @@ -2431,154 +2418,144 @@ body[data-pathname^="/data/benchmarking"] { .static-section-entry>.section-title { display: none; } - .benchmarking-ui-container { + .sliding-sidebar-ui-container { // Header and description text - .benchmarking-layout-container { - width: 100%; - .benchmarking-layout{ - >.nav-tabs { - >.nav-item { - .nav-link { - color: #5D5E63; - font-family: Inter; - font-size: 1rem; - font-weight: 400; - border-bottom: none; - - &.active { + .sliding-sidebar-layout-container .benchmarking-layout{ + >.nav-tabs { + >.nav-item { + .nav-link { + color: #5D5E63; + font-family: Inter; + font-size: 1rem; + font-weight: 400; + border-bottom: none; + + &.active { + color: #343741; + font-weight: 600; + border-top: 4px solid #E99415; + + .badge { color: #343741; - font-weight: 600; - border-top: 4px solid #E99415; - - .badge { - color: #343741; - } - } - &.disabled { - color: #9BA5B7; } - - &-title { - display: flex; - justify-content: center; - - .badge { - background-color: #F2F2F2; - color: #5D5E63; - margin: auto; - margin-left: 5px; - font-weight: 600; - } + } + &.disabled { + color: #9BA5B7; + } + + &-title { + display: flex; + justify-content: center; + + .badge { + background-color: #F2F2F2; + color: #5D5E63; + margin: auto; + margin-left: 5px; + font-weight: 600; } } } } + } - .tab-content { - .embedded-search-container { - >div { - flex-direction: column; - } + .tab-content { + .embedded-search-container { + >div { + flex-direction: column; } } - - >.row { - .information-container { - padding: 10px; - margin-bottom: 20px; - - .title { - color: #343741; + } + + >.row { + .information-container { + padding: 10px; + margin-bottom: 20px; + + .title { + color: #343741; + font-family: Inter; + font-size: 1.5rem; + font-weight: 600; + margin-top: 5px; + } + .description { + font-family: Inter; + font-size: 0.875rem; + color: #5D5E63; + line-height: 20px; + + .disclaimer { + color: #5D5E63; font-family: Inter; - font-size: 1.5rem; - font-weight: 600; - margin-top: 5px; + font-size: 0.875rem; + line-height: 20px; + margin-top: 10px; + span { + font-weight: 500; + } } - .description { + } + .callout { + margin-top: 24px; + border-radius: 7px; + max-width: 980px; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + + &-text { font-family: Inter; - font-size: 0.875rem; color: #5D5E63; + font-size: 0.875rem; + padding: 8px; line-height: 20px; - - .disclaimer { - color: #5D5E63; - font-family: Inter; - font-size: 0.875rem; - line-height: 20px; - margin-top: 10px; - span { - font-weight: 500; - } + + .flag { + font-weight: 600; } - } - .callout { - margin-top: 24px; - border-radius: 7px; - max-width: 980px; - border-top-left-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; - - &-text { - font-family: Inter; - color: #5D5E63; - font-size: 0.875rem; - padding: 8px; - line-height: 20px; - - .flag { - font-weight: 600; - } - .headline { - font-weight: 600; - } + .headline { + font-weight: 600; } - &.warning { - background-color: #FFF9F9; - border: 1px solid #F6D6D6; - border-left: 4px solid #BB3F3F; - - .flag { - font-weight: 600; - color: #BB3F3F; - } + } + &.warning { + background-color: #FFF9F9; + border: 1px solid #F6D6D6; + border-left: 4px solid #BB3F3F; + + .flag { + font-weight: 600; + color: #BB3F3F; } } + } - .toggle-information-text-button { - display: none; - } + .toggle-information-text-button { + display: none; } } + } - &-title { - display: flex; - justify-content: center; + &-title { + display: flex; + justify-content: center; - .badge { - background-color: #F2F2F2; - color: #5D5E63; - margin: auto; - margin-left: 5px; - font-weight: 600; - } + .badge { + background-color: #F2F2F2; + color: #5D5E63; + margin: auto; + margin-left: 5px; + font-weight: 600; } } } - - // Side nav - .benchmarking-nav-container { - display: none; - } @include media-breakpoint-up(sm) { - .benchmarking-layout-container { - .benchmarking-layout { - .tab-content { - .embedded-search-container { - >div { - flex-direction: row; - } + .sliding-sidebar-layout-container .benchmarking-layout { + .tab-content { + .embedded-search-container { + >div { + flex-direction: row; } } } @@ -2586,216 +2563,166 @@ body[data-pathname^="/data/benchmarking"] { } @include media-breakpoint-up(lg) { - display: flex; - flex: 1; - padding: 0px; // Header and description text - .benchmarking-layout-container { - flex: 1; - padding: 20px 32px 20px 20px; - overflow: scroll; - - .benchmarking-layout { - .page-description { - .information-container { - margin-bottom: 0px; - padding: 0px 0px 20px 10px; - - .title-container { - display: flex; - flex-direction: row; - margin-top: 5px; - margin-bottom: 20px; - .title { - margin: 0px; - } - } - .toggle-information-text-button { - position: absolute; - display: flex; - bottom: 0px; - background-color: transparent; - border: none; - border-radius: 4px; - margin: 10px 0px; - color: $link-color; - font-size: 0.875rem; - font-weight: 500; - - .icon { - margin: auto 8px auto auto; - } - - .toggle-information-text { - margin: auto; - height: 25px; - } - - &:hover { - font-weight: 600; - } + .sliding-sidebar-layout-container .benchmarking-layout { + .page-description { + .information-container { + margin-bottom: 0px; + padding: 0px 0px 20px 10px; + + .title-container { + display: flex; + flex-direction: row; + margin-top: 5px; + margin-bottom: 20px; + .title { + margin: 0px; } } + .toggle-information-text-button { + position: absolute; + display: flex; + bottom: 0px; + background-color: transparent; + border: none; + border-radius: 4px; + margin: 10px 0px; + color: $link-color; + font-size: 0.875rem; + font-weight: 500; + + .icon { + margin: auto 8px auto auto; + } - .body-container { - &.expanded { - max-height: 400px; - transition: max-height 150ms ease-in-out; - overflow: hidden; - margin-bottom: 1.5rem; + .toggle-information-text { + margin: auto; + height: 25px; } - &.collapsed { - max-height: 40px; - transition: max-height 150ms ease-in-out; - overflow: hidden; - margin-bottom: 1.5rem; - display: -webkit-box; - @include prefix(line-clamp, 2); - @include prefix(box-orient, vertical); + + &:hover { + font-weight: 600; } } } - >nav.nav-tabs { - a.nav-link { - text-align: left; + .body-container { + &.expanded { + max-height: 400px; + transition: max-height 150ms ease-in-out; + overflow: hidden; + margin-bottom: 1.5rem; + } + &.collapsed { + max-height: 40px; + transition: max-height 150ms ease-in-out; + overflow: hidden; + margin-bottom: 1.5rem; + display: -webkit-box; + @include prefix(line-clamp, 2); + @include prefix(box-orient, vertical); } } + } + + >nav.nav-tabs { + a.nav-link { + text-align: left; + } + } - .tab-content { - .embedded-search-container { - .search-view-controls-and-results { - .facets-column { + .tab-content { + .embedded-search-container { + .search-view-controls-and-results { + .facets-column { + transition: max-height 150ms ease-in-out; + } + .results-column { + .react-infinite-container { transition: max-height 150ms ease-in-out; } - .results-column { - .react-infinite-container { - transition: max-height 150ms ease-in-out; - } - } } } } } } + // Side nav - .benchmarking-nav-container { - display: flex; - min-height: calc(100vh - 236px); - padding: 0; - - .benchmarking-nav { - width: 100%; - position: relative; - padding: 25px 0px 0px 0px; + .sliding-sidebar-nav-container .sliding-sidebar-nav { + &-section { + &-title { + margin-bottom: 10px; + } + } - &-section { - &-title { - margin-bottom: 10px; + .accordion > ul { + list-style-type: none; + padding-left: 0; + gap: 10px; + display: flex; + flex-direction: column; + + > li > div.collapse > ul, + > li > div.collapsing > ul { + list-style-type: none; + padding-left: 0; + > li { + padding-left: 15px; } } - - .accordion > ul { - list-style-type: none; - padding-left: 0; - gap: 10px; - display: flex; - flex-direction: column; - - > li > div.collapse > ul, - > li > div.collapsing > ul { - list-style-type: none; - padding-left: 0; - > li { - padding-left: 15px; - } - } - - li.sidenav-link { - font-family: Inter; - font-size: 0.875rem; - font-weight: 400; - - > a { - color: #717378; + + li.sidenav-link { + font-family: Inter; + font-size: 0.875rem; + font-weight: 400; + + > a { + color: #717378; - &:hover { - text-decoration-color: $secondary !important; - } + &:hover { + text-decoration-color: $secondary !important; } - + } + + &.top { + font-size: 1rem; + } + &.active { + font-weight: 500; &.top { - font-size: 1rem; + font-weight: 700; } - &.active { - font-weight: 500; - &.top { - font-weight: 700; - } - &:not(.top) { - border-radius: 4px; - border: 1px solid #E2ECF2; - background: #EBF3F9; - } - - > a { - color: #343741; - text-decoration-color: $dark !important; - } + &:not(.top) { + border-radius: 4px; + border: 1px solid #E2ECF2; + background: #EBF3F9; } - } - - span.navlink-drop { - color: #717378; - font-size: 1rem; - font-weight: 400; - font-family: Inter; - text-align: left; - &.active { + + > a { color: #343741; - font-weight: 700; + text-decoration-color: $dark !important; } } } - - .toggle-button { - position: absolute; - display: flex; - justify-content: center; - border-radius: 50%; - border: 1px solid #DEE2E6; - width: 26px; - height: 26px; - right: -13px; - z-index: 2; - background-color: #FCFDFF; - color: #343741; - i { - font-size: 0.75rem; - margin: auto; - } - - &:hover { - background-color: #F6F6F6; - } - - &:active { - background-color: #f2f2f2; + span.navlink-drop { + color: #717378; + font-size: 1rem; + font-weight: 400; + font-family: Inter; + text-align: left; + &.active { + color: #343741; + font-weight: 700; } } } } &.show-nav { - padding-left: 32px; - .benchmarking-nav-container{ - width: 20%; - max-width: 300px; - border-right: 1px solid #dee2e6; - transition: width 100ms ease-in-out; - .benchmarking-nav { + .sliding-sidebar-nav-container{ + .sliding-sidebar-nav { width: 100%; padding-right: 20px; @@ -2811,18 +2738,10 @@ body[data-pathname^="/data/benchmarking"] { } } } - .benchmarking-layout-container { - width: 80%; - } } &.collapse-nav { - flex-wrap: nowrap; - .benchmarking-nav-container { - width: 32px; - border-right: 1px solid #E7F0F3; - background-color: #FBFBFC; - - .benchmarking-nav { + .sliding-sidebar-nav-container { + .sliding-sidebar-nav { width: 100%; .benchmarking-nav-section { display: none; diff --git a/src/encoded/types/aligned_reads.py b/src/encoded/types/aligned_reads.py index af6beeb63..75fee8bfa 100644 --- a/src/encoded/types/aligned_reads.py +++ b/src/encoded/types/aligned_reads.py @@ -3,6 +3,12 @@ from .submitted_file import SubmittedFile +def _build_aligned_reads_embedded_list(): + """Embeds for search on aligned reads files.""" + return SubmittedFile.embedded_list + [ + "reference_genome.display_title", + ] + @collection( name="aligned-reads", unique_key="submitted_id", @@ -14,4 +20,4 @@ class AlignedReads(SubmittedFile): item_type = "aligned_reads" schema = load_schema("encoded:schemas/aligned_reads.json") - embedded_list = SubmittedFile.embedded_list + embedded_list = _build_aligned_reads_embedded_list() diff --git a/src/encoded/types/file.py b/src/encoded/types/file.py index bb0f50245..6ba58fad6 100644 --- a/src/encoded/types/file.py +++ b/src/encoded/types/file.py @@ -374,6 +374,14 @@ def _build_file_embedded_list() -> List[str]: "software.code", "software.title", "software.version", + + # For browse search columns + "donors.display_title", + "sample_summary.tissues", + + # For facets + "donors.age", + "donors.sex" ] diff --git a/src/encoded/types/output_file.py b/src/encoded/types/output_file.py index 5fdd38087..fa5f5e3d9 100644 --- a/src/encoded/types/output_file.py +++ b/src/encoded/types/output_file.py @@ -3,6 +3,11 @@ from .acl import ONLY_ADMIN_VIEW_ACL from .file import File +def _build_output_file_embedded_list(): + """Embeds for search on output files.""" + return File.embedded_list + [ + "reference_genome.display_title", + ] def _build_output_file_embedded_list(): """Embeds for search on cell cultures.""" diff --git a/src/encoded/types/reference_file.py b/src/encoded/types/reference_file.py index e316b932d..e54053b22 100644 --- a/src/encoded/types/reference_file.py +++ b/src/encoded/types/reference_file.py @@ -15,4 +15,4 @@ class ReferenceFile(File): item_type = "reference_file" schema = load_schema("encoded:schemas/reference_file.json") - embedded_list = [] + embedded_list = ["reference_genome.display_title"] diff --git a/src/encoded/types/supplementary_file.py b/src/encoded/types/supplementary_file.py index d4f4d6620..b74799c43 100644 --- a/src/encoded/types/supplementary_file.py +++ b/src/encoded/types/supplementary_file.py @@ -5,7 +5,9 @@ def _build_supplementary_file_embedded_list(): """Embeds for search on supplementary files.""" - return SubmittedFile.embedded_list + return SubmittedFile.embedded_list + [ + "reference_genome.display_title", + ] @collection( diff --git a/src/encoded/types/variant_calls.py b/src/encoded/types/variant_calls.py index dc39f8a5f..e04a2148d 100644 --- a/src/encoded/types/variant_calls.py +++ b/src/encoded/types/variant_calls.py @@ -2,6 +2,11 @@ from .submitted_file import SubmittedFile +def _build_variant_calls_embedded_list(): + """Embeds for search on variant calls files.""" + return SubmittedFile.embedded_list + [ + "reference_genome.display_title", + ] @collection( name="variant-calls", @@ -13,4 +18,4 @@ class VariantCalls(SubmittedFile): item_type = "variant_calls" schema = load_schema("encoded:schemas/variant_calls.json") - embedded_list = SubmittedFile.embedded_list + embedded_list = _build_variant_calls_embedded_list()