diff --git a/frontend/src/js/dialog/wb-browse-dialog-collection-content.js b/frontend/src/js/dialog/wb-browse-dialog-collection-content.js
index b58ac2d..2c757f4 100644
--- a/frontend/src/js/dialog/wb-browse-dialog-collection-content.js
+++ b/frontend/src/js/dialog/wb-browse-dialog-collection-content.js
@@ -1,11 +1,115 @@
import { h, Component } from 'preact';
+import WBManifestWorkerWrapper from 'wb-manifest-worker-wrapper';
+import makeArvadosRequest from 'make-arvados-request';
+import WBTable from 'wb-table';
+import WBPagination from 'wb-pagination';
+
+function unescapeName(name) {
+ return name.replace(/(\\\\|\\[0-9]{3})/g,
+ (_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8))));
+}
class WBBrowseDialogCollectionContent extends Component {
- render() {
+ constructor(...args) {
+ super(...args);
+ this.state.manifestWorker = new WBManifestWorkerWrapper();
+ this.state.mode = 'manifestDownload';
+ this.state.rows = [];
+ }
+
+ componentDidMount() {
+ const { app, collectionUuid } = this.props;
+ const { arvHost, arvToken } = app.state;
+ const { manifestWorker } = this.state;
+
+ let prom = makeArvadosRequest(arvHost, arvToken,
+ '/arvados/v1/collections/' + collectionUuid);
+
+ let streams;
+
+ prom = prom.then(xhr => {
+ streams = xhr.response.manifest_text.split('\n');
+ const paths = streams.filter(s => s).map(s => {
+ const n = s.indexOf(' ');
+ return unescapeName(s.substr(0, n));
+ });
+
+ return manifestWorker.postMessage([ 'precreatePaths', paths ]);
+ });
+
+ prom = prom.then(() => {
+ this.setState({ 'mode': 'manifestParse' });
+ let prom_1 = new Promise(accept => accept());
+ for (let i = 0; i < streams.length; i++) {
+ prom_1 = prom_1.then(() => manifestWorker.postMessage([ 'parseStream', streams[i] ]));
+ prom_1 = prom_1.then(() => manifestWorker.postMessage([ 'listDirectory', '.' + this.props.collectionPath, true ]));
+ prom_1 = prom_1.then(e => this.prepareRows(e.data[1]));
+ }
+ return prom_1;
+ });
+
+ prom = prom.then(() => manifestWorker.postMessage([ 'listDirectory', '.' + this.props.collectionPath, true ]));
+ prom = prom.then(e => {
+ this.state.mode = 'browsingReady';
+ this.prepareRows(e.data[1])
+ });
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.props = nextProps;
+ if (this.state.mode !== 'browsingReady')
+ return;
+ let prom = this.state.manifestWorker.postMessage([
+ 'listDirectory', '.' + this.props.collectionPath, true
+ ]);
+ prom = prom.then(e => this.prepareRows(e.data[1]));
+ }
+
+ prepareRows(listing) {
+ const { makeSelectionCell, collectionPath, navigate,
+ page, itemsPerPage, collectionUuid, textSearch } = this.props;
+ const textLower = textSearch.toLowerCase();
+ listing = listing.filter(it => (it[1].toLowerCase().indexOf(textLower) !== -1));
+ const numPages = Math.ceil(listing.length / itemsPerPage);
+ const rows = listing.slice(page * itemsPerPage,
+ (page + 1) * itemsPerPage).map(it => [
+ makeSelectionCell(collectionUuid + '/' + collectionPath + '/' + it[1]),
+ it[0] === 'd' ? (
+ {
+ e.preventDefault();
+ navigate({ 'collectionPath': collectionPath + '/' + it[1],
+ 'bottomPage': 0 });
+ } }>{ it[1] }
+ ) : it[1],
+ it[0] === 'f' ? filesize(it[2]) : ''
+ ]);
+ this.setState({ rows, numPages });
+ }
+
+ render({ page, navigate }, { rows, mode, numPages }) {
return (
-
WBBrowseDialogCollectionContent
+
+ { mode === 'browsingReady' ? (
+ null
+ ) : [
+
{ mode === 'manifestParse' ? 'Parsing manifest...' : 'Downloading manifest...' }
,
+
+ ] }
+
+
navigate({ 'bottomPage': i }) } />
+
);
}
}
+WBBrowseDialogCollectionContent.defaultProps = {
+ 'itemsPerPage': 20
+};
+
export default WBBrowseDialogCollectionContent;
diff --git a/frontend/src/js/dialog/wb-browse-dialog-collection-list.js b/frontend/src/js/dialog/wb-browse-dialog-collection-list.js
index 41d26e5..3f934a2 100644
--- a/frontend/src/js/dialog/wb-browse-dialog-collection-list.js
+++ b/frontend/src/js/dialog/wb-browse-dialog-collection-list.js
@@ -25,7 +25,7 @@ class WBBrowseDialogCollectionList extends Component {
] : []).concat([
(
{ e.preventDefault();
- navigate('/browse-dialog/content/' + it.uuid); } }>{ it.name }
+ navigate('/browse-dialog/content/' + it.uuid + '////'); } }>{ it.name }
),
it.uuid
]));
diff --git a/frontend/src/js/dialog/wb-browse-dialog.js b/frontend/src/js/dialog/wb-browse-dialog.js
index feddf26..5c91caa 100644
--- a/frontend/src/js/dialog/wb-browse-dialog.js
+++ b/frontend/src/js/dialog/wb-browse-dialog.js
@@ -13,7 +13,7 @@ import { createHashHistory } from 'history';
// /browse-dialog/browse/( owner-uuid )/( project-page )/( text-search )
// /browse-dialog/users//( users-page )/( text-search )
// /browse-dialog/shared-with-me//( project-page )/( collection-page )/( text-search )
-// /browse-dialog/content/( collection-uuid )//( content-page )/( text-search )
+// /browse-dialog/content/( collection-uuid )//( content-page )/( text-search )/( collection-path )
//
// general pattern therefore:
// /browse-dialog/( mode )/( uuid )/( top-page )/( bottom-page )/( text-search )
@@ -40,6 +40,8 @@ class WBBrowseDialog extends Component {
this.state.mode = 'browse';
this.state.topPage = 0;
this.state.bottomPage = 0;
+ this.state.collectionPath = '';
+ this.state.textSearch = '';
}
navigateBack() {
@@ -56,7 +58,8 @@ class WBBrowseDialog extends Component {
'uuid' in url ? url.uuid : this.state.uuid,
'topPage' in url ? url.topPage : this.state.topPage,
'bottomPage' in url ? url.bottomPage : this.state.bottomPage,
- 'textSearch' in url ? url.textSearch : this.state.textSearch
+ 'textSearch' in url ? url.textSearch : this.state.textSearch,
+ encodeURIComponent('collectionPath' in url ? url.collectionPath : this.state.collectionPath)
].join('/');
}
@@ -64,12 +67,13 @@ class WBBrowseDialog extends Component {
if (useHistory)
this.state.history.push(this.state.currentUrl);
- let [ _1, _2, mode, uuid, topPage, bottomPage, textSearch ] = url.split('/');
+ let [ _1, _2, mode, uuid, topPage, bottomPage, textSearch, collectionPath ] = url.split('/');
topPage = parseInt(topPage, 10) || 0;
bottomPage = parseInt(bottomPage, 10) || 0;
+ collectionPath = decodeURIComponent(collectionPath);
this.setState({
'currentUrl': url,
- mode, uuid, topPage, bottomPage, textSearch
+ mode, uuid, topPage, bottomPage, textSearch, collectionPath
});
}
@@ -130,7 +134,11 @@ class WBBrowseDialog extends Component {
);
}
- render({ app, id, selectMany, selectWhat }, { history, currentUrl, mode, uuid, topPage, bottomPage, textSearch }) {
+ render({ app, id, selectMany, selectWhat },
+ { history, currentUrl, mode, uuid,
+ topPage, bottomPage, textSearch,
+ collectionPath }) {
+
return (
@@ -197,8 +205,12 @@ class WBBrowseDialog extends Component {
{ (mode === 'content') ? (
Content
-
+ this.makeSelectionCell(uuid) }
+ navigate={ url => this.navigate(url) }
+ textSearch={ textSearch } />
) : (selectWhat !== 'owner' && mode === 'browse') ? (