Skip to content

Commit 174c29d

Browse files
authored
Merge pull request #1637 from 4dn-dcic/mobile_ux_updates
Mobile UX Updates
2 parents 91d5262 + d945278 commit 174c29d

File tree

23 files changed

+274
-134
lines changed

23 files changed

+274
-134
lines changed

deploy/post_deploy_testing/cypress/integration/04a_search_views_local.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe('Deployment/CI Search View Tests', function () {
131131
.get('.search-results-container .search-result-row').then(($searchResultElems)=>{
132132
expect($searchResultElems.length).to.be.greaterThan(0);
133133
}).end()
134-
.get('.above-results-table-row .results-count.box button.btn-xs').contains("Create New Configuration").click().end().wait(1000)
134+
.get('.above-results-table-row .results-count.box button.btn-xs').contains("Create New").click().end().wait(1000)
135135
.get('a.dropdown-item').contains('Tier 1').click().end();
136136

137137
// set microscope conf. name

package-lock.json

Lines changed: 26 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
"micro-meta-app-react": "git+https:github.com/WU-BIMAC/MicroMetaApp-React#0.0.0.21",
108108
"@fortawesome/fontawesome-free": "^5.15.4",
109109
"@hms-dbmi-bgm/react-workflow-viz": "0.1.7",
110-
"@hms-dbmi-bgm/shared-portal-components": "git+https:github.com/4dn-dcic/shared-portal-components#0.1.42",
110+
"@hms-dbmi-bgm/shared-portal-components": "git+https:github.com/4dn-dcic/shared-portal-components#0.1.44",
111111
"auth0-lock": "^11.32.2",
112112
"d3": "^6.7.0",
113113
"date-fns": "^2.28.0",

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[tool.poetry]
22
# Note: Various modules refer to this system as "encoded", not "fourfront".
33
name = "encoded"
4-
version = "4.2.9" # 4.0.0 introduced containerization
4+
version = "4.2.10" # 4.0.0 introduced containerization
55
description = "4DN-DCIC Fourfront"
66
authors = ["4DN-DCIC Team <[email protected]>"]
77
license = "MIT"

src/encoded/root.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
import uptime
3+
import re
34

45
from collections import OrderedDict
56
from dcicutils import lang_utils
@@ -13,6 +14,10 @@
1314
from .appdefs import APP_VERSION_REGISTRY_KEY, ITEM_INDEX_ORDER
1415
from .schema_formats import is_accession
1516

17+
# for more information, visit http://detectmobilebrowsers.com/
18+
_IS_MOBILE_BROWSER_MATCH_B = re.compile(r"(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino", re.I|re.M)
19+
_IS_MOBILE_BROWSER_MATCH_V = re.compile(r"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-", re.I|re.M)
20+
1621

1722
def includeme(config):
1823
config.include(health_check)
@@ -341,3 +346,18 @@ def carousel(self, request):
341346
})
342347
def app_version(self, registry):
343348
return registry.settings[APP_VERSION_REGISTRY_KEY]
349+
350+
@calculated_property(schema={
351+
"title": "Is request initiated by a mobile device",
352+
"description": "The calculation is based on request.user_agent that is not reliable source. It is for server-side rendering, passing as a prop is not recommended.",
353+
"type": "boolean"
354+
})
355+
def is_mobile_browser(self, request):
356+
if hasattr(request, 'user_agent') and request.user_agent is not None:
357+
user_agent = request.user_agent
358+
b = _IS_MOBILE_BROWSER_MATCH_B.search(user_agent)
359+
v = _IS_MOBILE_BROWSER_MATCH_V.search(user_agent[0:4])
360+
if b or v:
361+
return True
362+
# fallback
363+
return False

src/encoded/static/components/app.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,7 @@ class BodyElement extends React.PureComponent {
17101710
const appClass = slowLoad ? 'communicating' : 'done';
17111711
const overlaysContainer = this.overlaysContainerRef.current;
17121712
const isSelectPage = isSelectAction(currentAction) && this.memoized.isSearchPage(href);
1713+
const { is_mobile_browser: isMobileBrowser = false } = context;
17131714

17141715
if (hasError) return this.renderErrorState();
17151716

@@ -1719,6 +1720,11 @@ class BodyElement extends React.PureComponent {
17191720
windowWidth, windowHeight, isFullscreen, overlaysContainer
17201721
};
17211722

1723+
const initialFields = [
1724+
isMobileBrowser ? 'experiments_in_set.biosample.biosource.biosource_type' : 'experiments_in_set.experiment_type.display_title',
1725+
'experiments_in_set.biosample.biosource.organism.name'
1726+
];
1727+
17221728
return (
17231729
<body data-current-action={currentAction} onClick={onBodyClick} onSubmit={onBodySubmit} data-path={hrefParts.path}
17241730
data-pathname={hrefParts.pathname} className={this.bodyClassName()}>
@@ -1754,7 +1760,7 @@ class BodyElement extends React.PureComponent {
17541760

17551761
<div id="facet-charts-container" className="container">
17561762
<FacetCharts {..._.pick(this.props, 'context', 'href', 'session', 'schemas', 'browseBaseState')}
1757-
{...{ windowWidth, windowHeight, navigate, isFullscreen }} />
1763+
{...{ windowWidth, windowHeight, navigate, isFullscreen, initialFields }} />
17581764
</div>
17591765

17601766
<ContentErrorBoundary canonical={canonical} href={href}>

src/encoded/static/components/browse/MicroscopySearchView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ const CreateNewConfigurationDropDownButton = React.memo(function (props) {
337337
const tierOptions = _.range(startTier, endTier + 1);
338338
return (
339339
<DropdownButton id="tier-selector" onSelect={handleChangeMicroscopeTier}
340-
title="Create New Configuration" size="xs" disabled={disabled}>
340+
title="Create New" size="xs" disabled={disabled}>
341341
{tierOptions.map((opt, i) => (
342342
<DropdownItem key={opt} eventKey={opt} data-key={opt}>
343343
{'Tier ' + opt}

src/encoded/static/components/browse/components/above-table-controls/SelectedFilesDownloadButton.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import _ from 'underscore';
77
import memoize from 'memoize-one';
88
import Modal from 'react-bootstrap/esm/Modal';
99

10-
import { console, ajax, JWT, typedefs, analytics } from '@hms-dbmi-bgm/shared-portal-components/es/components/util';
10+
import { console, ajax, JWT, typedefs, analytics, object } from '@hms-dbmi-bgm/shared-portal-components/es/components/util';
1111
import { display as dateTimeDisplay } from '@hms-dbmi-bgm/shared-portal-components/es/components/ui/LocalizedTime';
1212
import { uniqueFileCount, fileCountWithDuplicates } from './../SelectedFilesController';
1313
import { onLoginNavItemClick } from './../../../navigation/components/LoginNavItem';
@@ -208,9 +208,9 @@ class SelectedFilesDownloadModal extends React.PureComponent {
208208
<Modal.Body>
209209
<div className="important-notes-section">
210210
<h4 className="mb-07 text-500">Important</h4>
211-
<ul className="mb-25">
211+
<ul>
212212
<li className="mb-05">
213-
<span className="text-danger"><b>As of October 15, 2020</b>, you must include an <b>access key</b> in your cURL command for bulk downloads.</span>
213+
<span className="text-danger">You must include an <b>access key</b> in your cURL command for bulk downloads.</span>
214214
</li>
215215
<li className="mb-05">You can configure the access key in {session ? <a href={profileHref} target="_blank" rel="noopener noreferrer">your profile</a> : 'your profile'}, then use it in place of <em>{'<access_key_id>:<access_key_secret>'}</em>, below.</li>
216216
{!session ?
@@ -225,7 +225,7 @@ class SelectedFilesDownloadModal extends React.PureComponent {
225225
{ /*session || */foundUnpublishedFiles ?
226226
<div className="extra-notes-section">
227227
<h4 className="mt-2 mb-07 text-500">Notes</h4>
228-
<ul className="mb-25">
228+
<ul className="mb-20">
229229
{/* { session ?
230230
<li className="mb-05">
231231
To download files which are not yet released, please include an <b>access key</b> in your cURL command which you can configure in <a href={profileHref} target="_blank" rel="noopener noreferrer">your profile</a>.
@@ -247,15 +247,15 @@ class SelectedFilesDownloadModal extends React.PureComponent {
247247
</div> : null }
248248

249249
{ foundUnpublishedFiles && !disclaimerAccepted?
250-
<button type="button" className="btn btn-info" onClick={this.handleAcceptDisclaimer}>
251-
<i className="icon icon-fw icon-check mr-05 fas"/>
250+
<button type="button" className="btn btn-info mr-1 mt-1 btn-block-xs-only" onClick={this.handleAcceptDisclaimer}>
251+
<i className="icon icon-fw icon-check fas mr-1"/>
252252
I have read and understand the notes.
253253
</button>
254254
:
255255
<SelectedFilesDownloadStartButton {...{ selectedFiles, suggestedFilename, context, action }} />
256256
}
257257

258-
<button type="reset" onClick={onHide} className="btn btn-outline-dark ml-05">Cancel</button>
258+
<button type="reset" onClick={onHide} className="btn btn-outline-dark mt-1 btn-block-xs-only">Cancel</button>
259259

260260
</Modal.Body>
261261
</Modal>
@@ -265,12 +265,19 @@ class SelectedFilesDownloadModal extends React.PureComponent {
265265

266266
const ModalCodeSnippet = React.memo(function ModalCodeSnippet(props){
267267
const { filename, session } = props;
268-
return (
269-
<pre className="mb-15">
270-
cut -f 1 <b>{ filename }</b> | tail -n +3 | grep -v ^# | xargs -n 1 curl -O -L
271-
{ session ? <code style={{ 'opacity' : 0.5 }}> --user <em>{'<access_key_id>:<access_key_secret>'}</em></code> : null }
268+
const htmlValue = (
269+
<pre className="mb-15 d-md-inline curl-command">
270+
cut -f 1 <b>{filename}</b> | tail -n +3 | grep -v ^# | xargs -n 1 curl -O -L
271+
{session ? <code style={{ 'opacity': 0.5 }}> --user <em>{'<access_key_id>:<access_key_secret>'}</em></code> : null}
272272
</pre>
273273
);
274+
const plainValue = `cut -f 1 ${filename} | tail -n +3 | grep -v ^# | xargs -n 1 curl -O -L` + (session ? " --user <access_key_id>:<access_key_secret>" : '');
275+
return (
276+
<object.CopyWrapper value={plainValue} className="curl-command-wrapper" data-tip={'Click to copy'}
277+
wrapperElement="div" iconProps={{ }}>
278+
{htmlValue}
279+
</object.CopyWrapper>
280+
);
274281
});
275282

276283

@@ -320,12 +327,12 @@ const SelectedFilesDownloadStartButton = React.memo(function SelectedFilesDownlo
320327
}, [ selectedFiles, context ]);
321328

322329
return (
323-
<form method="POST" action={action} className="d-inline-block">
330+
<form method="POST" action={action} className="d-inline-block d-block-xs-only">
324331
<input type="hidden" name="accession_triples" value={JSON.stringify(accessionTripleArrays)} />
325332
<input type="hidden" name="download_file_name" value={JSON.stringify(suggestedFilename)} />
326-
<button type="submit" name="Download" className="btn btn-primary" onClick={onClick}
333+
<button type="submit" name="Download" className="btn btn-primary mt-1 mr-1 btn-block-xs-only" onClick={onClick}
327334
data-tip="Details for each individual selected file delivered via a TSV spreadsheet.">
328-
<i className="icon icon-fw icon-file-alt fas"/>&nbsp; Download metadata for files
335+
<i className="icon icon-fw icon-file-alt fas mr-1"/>Download metadata for files
329336
</button>
330337
</form>
331338
);

0 commit comments

Comments
 (0)