diff --git a/src/frontend/static/frontend/src/components/Base.tsx b/src/frontend/static/frontend/src/components/Base.tsx index 282066ca..2ffa1855 100644 --- a/src/frontend/static/frontend/src/components/Base.tsx +++ b/src/frontend/static/frontend/src/components/Base.tsx @@ -13,6 +13,7 @@ import en from '../locales/en' // Common dependencies for all the pages import 'fomantic-ui-css/semantic.css' import '../css/base.css' +import '../css/responsive.css' const messages = { en, es } diff --git a/src/frontend/static/frontend/src/components/MainNavbar.tsx b/src/frontend/static/frontend/src/components/MainNavbar.tsx index aa48b047..678e304d 100644 --- a/src/frontend/static/frontend/src/components/MainNavbar.tsx +++ b/src/frontend/static/frontend/src/components/MainNavbar.tsx @@ -169,160 +169,141 @@ const MainNavbar = (props: MainNavbarProps) => { const intl = useIntl() // Gets current user context const currentUser = useContext(CurrentUserContext) + const [menuOpen, setMenuOpen] = useState(false) const cBioPortalOption = ( ) - return ( - - {/* Logo */} - - {intl.formatMessage({ - - - {/* Loading spinners while user is fetch */} - {props.isLoadingUser && ( - - - - - - - - - - - - - - - )} - {/* Analysis menu */} + const renderNavbarItems = () => ( + <> {currentUser && !currentUser.is_anonymous && ( <> - - - - {/* GEM panel */} - - - {/* Survival Analysis panel */} - {/* TODO: discuss with team! Maybe this is the "Stats validation panel in Biomarkers page" */} - {/* */} - - {/* Biomarkers panel */} - - - {/* Differential Expression panel */} - - - - - - {/* Datasets menu */} - - - - {/* User's Datasets panel */} - - - {/* cBioPortal Datasets panel */} - {cBioPortalOption} - - - - - {/* Institutions */} - - - {intl.formatMessage({ id: 'mainNavbar.institutions' })} - - - - )} + + + - {/* Only admin options */} - {currentUser && (currentUser.is_superuser || currentUser.is_institution_admin) && ( - - + + + + + + + - {currentUser.is_superuser && ( - <> - {/* User's Datasets panel */} - - - )} + + + {cBioPortalOption} - + + + {intl.formatMessage({ id: 'mainNavbar.institutions' })} + + )} - {/* About us */} - - - {intl.formatMessage({ id: 'mainNavbar.aboutUs' })} - - - - - - {intl.formatMessage({ id: 'mainNavbar.faq' })} - - + {currentUser && (currentUser.is_superuser || currentUser.is_institution_admin) && ( + + + {currentUser.is_superuser && ( + + )} + + + )} + + + {intl.formatMessage({ id: 'mainNavbar.aboutUs' })} + - - - {intl.formatMessage({ id: 'mainNavbar.openSource' })} + + {intl.formatMessage({ id: 'mainNavbar.faq' })} + + + + {intl.formatMessage({ id: 'mainNavbar.openSource' })} + + + + + ) + + return ( + <> + + + {intl.formatMessage({ - - {/* LogIn/LogOut panel */} - - - - + + setMenuOpen(!menuOpen)} aria-label='Open menu'> + + + + + {props.isLoadingUser && ( + + + + + + + + + + + + + + + )} + + + {renderNavbarItems()} + + + + {menuOpen && ( + + {renderNavbarItems()} + + )} + ) } diff --git a/src/frontend/static/frontend/src/components/common/PaginatedTable.tsx b/src/frontend/static/frontend/src/components/common/PaginatedTable.tsx index c91ee9aa..314be36c 100644 --- a/src/frontend/static/frontend/src/components/common/PaginatedTable.tsx +++ b/src/frontend/static/frontend/src/components/common/PaginatedTable.tsx @@ -1,6 +1,6 @@ import ky from 'ky' import React, { ReactElement } from 'react' -import { Checkbox, DropdownItemProps, Form, Grid, Header, Icon, Pagination, SemanticWIDTHS, SemanticWIDTHSNUMBER, Table } from 'semantic-ui-react' +import { Accordion, Checkbox, DropdownItemProps, Form, Grid, Header, Icon, Pagination, SemanticWIDTHS, SemanticWIDTHSNUMBER, Table } from 'semantic-ui-react' import { RowHeader } from '../../utils/django_interfaces' import { GeneralTableControl, Nullable, ResponseRequestWithPagination, WebsocketConfig } from '../../utils/interfaces' import { getDefaultGeneralTableControl, getDefaultPageSizeOption, alertGeneralError, generatesOrderingQuery } from '../../utils/util_functions' @@ -112,6 +112,7 @@ interface PaginatedTableProps { infoPopupContent?: string, /** `width` prop of Form.Item of the _Entries_ select. */ entriesSelectWidth?: SemanticWIDTHS, + mobileFiltersLabel?: string, /** Callback to render custom components applied to data retrieved from backend API */ mapFunction: (elem: T) => ReactElement intl: IntlShape @@ -131,7 +132,8 @@ interface PaginatedTableState { } }, elements: T[], - gettingData: boolean + gettingData: boolean, + mobileFiltersOpen: boolean } /** @@ -176,7 +178,8 @@ class PaginatedTable extends React.Component, Paginate elements: [], tableControl: generalTableControl, retrievedOptions: {}, - gettingData: false + gettingData: false, + mobileFiltersOpen: false } } @@ -481,6 +484,43 @@ class PaginatedTable extends React.Component, Paginate ) : tableBody + const filtersForm = ( +
+ + {this.props.customElements} + + {this.props.showSearchInput && ( + { + this.handleTableControlChanges(name, value) + }} + /> + )} + {customFilters} + { + this.handleTableControlChanges(name, value) + }} + /> + +
+ ) + return ( @@ -501,48 +541,30 @@ class PaginatedTable extends React.Component, Paginate )} -
- - {this.props.customElements} - - {/* Search input */} - {this.props.showSearchInput && ( - { - this.handleTableControlChanges(name, value) - }} - /> - )} - {customFilters} - {/* Page size */} - { - this.handleTableControlChanges(name, value) - }} - /> - -
+ {this.props.mobileFiltersLabel + ? ( + + } + onClick={() => this.setState((prevState) => ({ mobileFiltersOpen: !prevState.mobileFiltersOpen }))} + > + {this.props.mobileFiltersLabel} + + + + {filtersForm} + + + ) + : filtersForm}
- + {/* Table */} - +
{/* Header */} diff --git a/src/frontend/static/frontend/src/components/pipeline/MiRNAPipeline.tsx b/src/frontend/static/frontend/src/components/pipeline/MiRNAPipeline.tsx index 6cac2445..f344cb6f 100644 --- a/src/frontend/static/frontend/src/components/pipeline/MiRNAPipeline.tsx +++ b/src/frontend/static/frontend/src/components/pipeline/MiRNAPipeline.tsx @@ -913,7 +913,14 @@ class MiRNAPipeline extends React.Component - + {this.state.activeTab === 'all-experiments' && ( + + +
GEM
+
+
+ )} + - - headerTitle='GEM' - updateWSKey='update_experiments' +
+ + headerTitle='GEM' + mobileFiltersLabel={intl.formatMessage({ id: 'allExperimentsView.filters.title' })} + updateWSKey='update_experiments' defaultSortProp={{ sortField: 'submit_date', sortOrderAscendant: false }} headers={[ { name: intl.formatMessage({ id: 'common.name' }), serverCodeToSort: 'name' }, diff --git a/src/frontend/static/frontend/src/components/site-policy/SitePolicy.tsx b/src/frontend/static/frontend/src/components/site-policy/SitePolicy.tsx index e126b6ab..141976cf 100644 --- a/src/frontend/static/frontend/src/components/site-policy/SitePolicy.tsx +++ b/src/frontend/static/frontend/src/components/site-policy/SitePolicy.tsx @@ -4,80 +4,86 @@ import { Base } from '../Base' import { ExternalLink } from '../common/ExternalLink' import { useIntl } from 'react-intl' +const SitePolicyContent = () => { + const intl = useIntl() + return ( + + + {/* Image */} + + + + + + + {/* Text */} + + +
+ {intl.formatMessage({ id: 'sitePolicy.header' })} +
+ +

+ {intl.formatMessage({ id: 'sitePolicy.authentication' })} + +
+ + {intl.formatMessage({ id: 'sitePolicy.dataTransfer' })} + +
+ + {intl.formatMessage( + { id: 'sitePolicy.firewall' }, + { multiomixLink: 'www.multiomix.org' } + )} + +
+ + {intl.formatMessage({ id: 'sitePolicy.containerized' })} + +
+ + {intl.formatMessage({ id: 'sitePolicy.securityMeasures' })} + +
+ + {intl.formatMessage( + { id: 'sitePolicy.piiRestriction' }, + { multiomixLink: 'www.multiomix.org' } + )} + +
+ + {intl.formatMessage( + { id: 'sitePolicy.localInstance' }, + { multiomixLink: 'www.multiomix.org' } + )}{' '} + {intl.formatMessage({ id: 'sitePolicy.localInstanceInstructions' })}{' '} + + https://github.com/omics-datascience/multiomix/blob/main/DEPLOYING.md + +

+
+
+
+
+ ) +} + /** * Site policy (terms and privacy policy) page * @returns Component */ export const SitePolicy = () => { - const intl = useIntl() return (
- - - {/* Image */} - - - - - - - {/* Text */} - - -
- {intl.formatMessage({ id: 'sitePolicy.header' })} -
- -

- {intl.formatMessage({ id: 'sitePolicy.authentication' })} - -
- - {intl.formatMessage({ id: 'sitePolicy.dataTransfer' })} - -
- - {intl.formatMessage( - { id: 'sitePolicy.firewall' }, - { multiomixLink: 'www.multiomix.org' } - )} - -
- - {intl.formatMessage({ id: 'sitePolicy.containerized' })} - -
- - {intl.formatMessage({ id: 'sitePolicy.securityMeasures' })} - -
- - {intl.formatMessage( - { id: 'sitePolicy.piiRestriction' }, - { multiomixLink: 'www.multiomix.org' } - )} - -
- - {intl.formatMessage( - { id: 'sitePolicy.localInstance' }, - { multiomixLink: 'www.multiomix.org' } - )}{' '} - {intl.formatMessage({ id: 'sitePolicy.localInstanceInstructions' })}{' '} - - https://github.com/omics-datascience/multiomix/blob/main/DEPLOYING.md - -

-
-
-
-
+
) diff --git a/src/frontend/static/frontend/src/css/gem.css b/src/frontend/static/frontend/src/css/gem.css index 449355f9..411e0125 100644 --- a/src/frontend/static/frontend/src/css/gem.css +++ b/src/frontend/static/frontend/src/css/gem.css @@ -67,6 +67,178 @@ border-color: #2185d0 !important; } +.gem-all-experiments-view .mobile-filters-toggle { + display: none !important; +} + +.gem-all-experiments-view .mobile-filters-content { + display: block !important; +} + +.gem-mobile-title-row { + display: none !important; +} + +@media only screen and (max-width: 767px) { + .gem-all-experiments-view .mobile-filters-accordion { + position: relative; + left: 1rem; + } + + .gem-mobile-title-row { + display: flex !important; + padding-bottom: 0 !important; + } + + .gem-mobile-title-row .ui.header { + margin: 0; + width: 100%; + } + + .gem-all-experiments-view .mobile-filters-toggle { + align-items: center; + background: #2185d0; + color: #fff; + display: flex !important; + justify-content: center; + padding: 0.78571429em 1em !important; + position: relative; + } + + .gem-all-experiments-view .mobile-filters-toggle > span { + text-align: center; + width: 100%; + } + + .gem-all-experiments-view .mobile-filters-toggle > .icon { + margin: 0 !important; + position: absolute; + right: 1em; + } + + .gem-all-experiments-view .mobile-filters-content { + display: none !important; + } + + .gem-all-experiments-view .mobile-filters-content.active { + display: block !important; + } + + .gem-all-experiments-view > .ui.padded.stackable.grid > .row:first-child { + margin-left: 1rem; + margin-right: 1rem; + width: calc(100% - 2rem) !important; + } + + .experiments-tabs-header { + flex-wrap: nowrap !important; + margin-left: 1rem; + margin-right: 1rem; + width: calc(100% - 2rem) !important; + } + + .experiments-tabs-header > .column { + padding-left: 0 !important; + padding-right: 0 !important; + } + + .experiments-tabs-header > .column:first-child { + flex: 1 1 auto !important; + min-width: 0 !important; + width: auto !important; + } + + .experiments-tabs-header > .column:last-child { + flex: 0 0 44px !important; + width: 44px !important; + } + + .experiments-tabs-header .menu-with-bolder-border { + max-width: 100%; + min-width: 0; + } + + .gem-all-experiments-view { + max-width: 100%; + min-width: 0; + } + + .gem-all-experiments-view h4.ui.header.margin-bottom-1 { + display: none; + } + + .gem-all-experiments-view .custom-form { + display: block; + } + + .gem-all-experiments-view .custom-form > .field { + margin: 0 0 1em !important; + width: 100% !important; + } + + .gem-all-experiments-view .custom-form > .field:last-child { + margin-bottom: 0 !important; + } + + .gem-all-experiments-view .paginated-table-scroll { + left: 1rem; + max-width: 100%; + min-width: 0; + width: 100%; + -webkit-overflow-scrolling: touch; + } + + .gem-all-experiments-view .paginated-table-scroll .ui.sortable.table > thead > tr > th { + white-space: normal; + } +} + +@media only screen and (min-width: 768px) and (max-width: 1024px) { + .experiments-tabs-header { + flex-wrap: nowrap !important; + margin-left: 1rem; + margin-right: 1rem; + width: calc(100% - 2rem) !important; + } + + .experiments-tabs-header > .column { + padding-left: 0 !important; + padding-right: 0 !important; + } + + .experiments-tabs-header > .column:first-child { + flex: 1 1 auto !important; + min-width: 0 !important; + width: auto !important; + } + + .experiments-tabs-header > .column:last-child { + flex: 0 0 44px !important; + width: 44px !important; + } + + .experiments-tabs-header .menu-with-bolder-border { + max-width: 100%; + min-width: 0; + } + + .gem-all-experiments-view { + max-width: 100%; + min-width: 0; + } + + .gem-all-experiments-view .entries-select-table { + min-width: 75px; + } + + .gem-all-experiments-view .paginated-table-scroll { + max-width: 100%; + min-width: 0; + width: 100% !important; + -webkit-overflow-scrolling: touch; + } +} + #label-new-experiment-selected-tag { width: 70% } @@ -205,4 +377,4 @@ #huge-size-msg-link { opacity: 1; text-decoration: underline; -} \ No newline at end of file +} diff --git a/src/frontend/static/frontend/src/css/index.css b/src/frontend/static/frontend/src/css/index.css index fa4dd829..623e0826 100644 --- a/src/frontend/static/frontend/src/css/index.css +++ b/src/frontend/static/frontend/src/css/index.css @@ -36,3 +36,13 @@ #source-button { min-width: 30%; } + +#main-app .ui.text.container { + max-width: min(100%, 700px); +} + +@media only screen and (min-width: 1151px) and (max-width: 1366px) { + #homepage-heading { + text-align: center; + } +} diff --git a/src/frontend/static/frontend/src/css/responsive.css b/src/frontend/static/frontend/src/css/responsive.css new file mode 100644 index 00000000..a04fe8f0 --- /dev/null +++ b/src/frontend/static/frontend/src/css/responsive.css @@ -0,0 +1,92 @@ +.ui.menu:not(.vertical) .right.menu.mobile-navbar-toggle, +.ui.vertical.menu.mobile-navbar-menu { + display: none !important; +} + +.ui.menu:not(.vertical) .menu.desktop-navbar-items { + display: flex !important; +} + +@media only screen and (max-width: 1024px) { + .ui.menu:not(.vertical) .menu.desktop-navbar-items { + display: none !important; + } + + .ui.menu:not(.vertical) .right.menu.mobile-navbar-toggle { + display: flex !important; + margin-left: auto !important; + } + + .ui.vertical.menu.mobile-navbar-menu { + display: block !important; + margin-top: 0 !important; + } + + + .ui.vertical.menu.mobile-navbar-menu .dropdown.item > .menu { + position: static; + width: 100%; + min-width: 100%; + max-width: 100%; + margin-top: 0.75rem; + box-shadow: none; + border-radius: 0.28571429rem; + } + + .navbar-loading-placeholders { + display: none !important; + } + + .mobile-navbar-toggle .item { + padding: 1rem 1.25rem !important; + } + + .mobile-navbar-toggle .icon { + font-size: 2rem !important; + } +} + +@media only screen and (min-width: 1025px) and (max-width: 1150px) { + .ui.menu:not(.vertical) .menu.desktop-navbar-items { + flex: 1 !important; + display: flex !important; + justify-content: center !important; + align-items: center !important; + } + + .ui.menu:not(.vertical) .right.menu.mobile-navbar-toggle, + .ui.vertical.menu.mobile-navbar-menu { + display: none !important; + } + + .desktop-navbar-items .item, + .desktop-navbar-items .dropdown { + font-size: 0.82rem !important; + padding-left: 0.45rem !important; + padding-right: 0.45rem !important; + } + + .ui.menu .header.item { + padding-right: 0.8rem !important; + } +} + +@media only screen and (min-width: 1151px) and (max-width: 1366px) { + .ui.menu:not(.vertical) .menu.desktop-navbar-items { + flex: 1 !important; + display: flex !important; + justify-content: center !important; + align-items: center !important; + } + + .desktop-navbar-items .item, + .desktop-navbar-items .dropdown { + font-size: 0.90rem !important; + padding-left: 0.75rem !important; + padding-right: 0.75rem !important; + } + + .ui.menu .header.item { + padding-right: 1.2rem !important; + } +} diff --git a/src/frontend/static/frontend/src/css/site-policy.css b/src/frontend/static/frontend/src/css/site-policy.css index fb60111c..0ecbc1bf 100644 --- a/src/frontend/static/frontend/src/css/site-policy.css +++ b/src/frontend/static/frontend/src/css/site-policy.css @@ -5,4 +5,8 @@ #site-policy-content { text-align: justify; font-size: large; -} \ No newline at end of file +} + +#site-policy-content a { + overflow-wrap: anywhere; +} diff --git a/src/frontend/static/frontend/src/locales/en.ts b/src/frontend/static/frontend/src/locales/en.ts index dc134bc4..fdbe260a 100644 --- a/src/frontend/static/frontend/src/locales/en.ts +++ b/src/frontend/static/frontend/src/locales/en.ts @@ -812,6 +812,12 @@ export default { 'loginSignUpForm.validEmailMessage': 'Please provide a valid email address', 'loginSignUpForm.passwordMismatchMessage': 'This value is different to Password field', // 91.OpenSource + 'openSource.header.main': 'Explore the open-source projects from', + 'openSource.header.sub': 'These repositories represent some of our most prominent open-source initiatives, developed to empower the research community with accessible and cutting-edge bioinformatics tools.', + 'openSource.publications.sub': 'In addition to our open-source software, we regularly publish peer-reviewed scientific articles that document the methodologies, innovations, and findings behind our tools. We invite you to explore our publications to better understand the research impact of our work.', + 'openSource.publications.multiomix.description': 'A cloud-based platform to infer cancer genomic and epigenomic events associated with gene expression modulation', + 'openSource.publications.modulector.description': 'A platform as a service for access to microRNA databases', + 'openSource.intro.title': 'At Omicsdatascience, we believe in open science. Explore our open-source projects, freely available to the community to foster collaboration, transparency, and innovation in biomedical research. Available in our GitHub organization.', 'openSource.intro.description': 'These repositories represent some of our most prominent open-source initiatives, developed to empower the research community with accessible and cutting-edge bioinformatics tools.', @@ -830,6 +836,7 @@ export default { 'allExperimentsView.filters.selectTag': 'Select an existing Tag', 'allExperimentsView.filters.experimentType': 'Experiment type', 'allExperimentsView.filters.correlationMethod': 'Correlation method', + 'allExperimentsView.filters.title': 'Filters', 'allExperimentsView.table.name': 'Name', 'allExperimentsView.table.description': 'Description', diff --git a/src/frontend/static/frontend/src/locales/es.ts b/src/frontend/static/frontend/src/locales/es.ts index 8ca219d2..4c628a91 100644 --- a/src/frontend/static/frontend/src/locales/es.ts +++ b/src/frontend/static/frontend/src/locales/es.ts @@ -861,6 +861,12 @@ export default { 'loginSignUpForm.validEmailMessage': 'Por favor ingrese una dirección de correo válida', 'loginSignUpForm.passwordMismatchMessage': 'Este valor es diferente al campo Contraseña', // 91.OpenSource + 'openSource.header.main': 'Explora los proyectos de código abierto de', + 'openSource.header.sub': 'Estos repositorios representan algunas de nuestras iniciativas de código abierto más destacadas, desarrolladas para brindar a la comunidad científica herramientas bioinformáticas accesibles y de vanguardia.', + 'openSource.publications.sub': 'Además de nuestro software de código abierto, publicamos regularmente artículos científicos revisados por pares que documentan las metodologías, innovaciones y hallazgos detrás de nuestras herramientas. Te invitamos a explorar nuestras publicaciones para comprender mejor el impacto científico de nuestro trabajo.', + 'openSource.publications.multiomix.description': 'Una plataforma basada en la nube para inferir eventos genómicos y epigenómicos del cáncer asociados con la modulación de la expresión génica', + 'openSource.publications.modulector.description': 'Una plataforma como servicio para el acceso a bases de datos de microARNs', + 'openSource.intro.title': 'En Omicsdatascience creemos en la ciencia abierta. Explora nuestros proyectos de código abierto, disponibles libremente para la comunidad con el fin de fomentar la colaboración, la transparencia y la innovación en la investigación biomédica. Disponibles en nuestra organización de GitHub.', 'openSource.intro.description': 'Estos repositorios representan algunas de nuestras iniciativas de código abierto más destacadas, desarrolladas para brindar a la comunidad científica herramientas bioinformáticas accesibles y de vanguardia.', @@ -879,6 +885,7 @@ export default { 'allExperimentsView.filters.selectTag': 'Seleccionar una etiqueta existente', 'allExperimentsView.filters.experimentType': 'Tipo de experimento', 'allExperimentsView.filters.correlationMethod': 'Método de correlación', + 'allExperimentsView.filters.title': 'Filtros', 'allExperimentsView.table.name': 'Nombre', 'allExperimentsView.table.description': 'Descripción', diff --git a/src/frontend/templates/frontend/about-us.html b/src/frontend/templates/frontend/about-us.html index 8e264027..04b06f28 100644 --- a/src/frontend/templates/frontend/about-us.html +++ b/src/frontend/templates/frontend/about-us.html @@ -6,10 +6,14 @@ {% block meta_description %}Omicsdatascience brings together experts in genomics, epigenomics, and data science to develop open-source tools, foster collaboration, and drive innovation in cancer research..{% endblock %} +{% block css %} + {% render_bundle 'aboutUs' 'css' %} +{% endblock %} + {% block content %}
{% endblock %} {% block js %} {% render_bundle 'aboutUs' 'js' %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/frontend/templates/frontend/faq.html b/src/frontend/templates/frontend/faq.html index 29c94675..7d7d377e 100644 --- a/src/frontend/templates/frontend/faq.html +++ b/src/frontend/templates/frontend/faq.html @@ -7,10 +7,14 @@ Frequently Asked Questions about Multiomix and our platform. {% endblock %} +{% block css %} + {% render_bundle 'faq' 'css' %} +{% endblock %} + {% block content %}
{% endblock %} {% block js %} {% render_bundle 'faq' 'js' %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/frontend/templates/frontend/open-source.html b/src/frontend/templates/frontend/open-source.html index bff6e881..d13fcb56 100644 --- a/src/frontend/templates/frontend/open-source.html +++ b/src/frontend/templates/frontend/open-source.html @@ -5,10 +5,14 @@ {% block title %} | Open source{% endblock %} {% block meta_description %}Discover and contribute to Omicsdatascience’s open-source initiatives on GitHub—powerful tools and libraries for multi-omics and cancer research, freely available for the community.{% endblock %} +{% block css %} + {% render_bundle 'openSource' 'css' %} +{% endblock %} + {% block content %}
{% endblock %} {% block js %} {% render_bundle 'openSource' 'js' %} -{% endblock %} \ No newline at end of file +{% endblock %}