diff --git a/frontend/src/js/component/wb-collection-content.js b/frontend/src/js/component/wb-collection-content.js
new file mode 100644
index 0000000..31f5816
--- /dev/null
+++ b/frontend/src/js/component/wb-collection-content.js
@@ -0,0 +1,45 @@
+import { h, Component } from 'preact';
+import WBTable from 'wb-table';
+import WBBreadcrumbs from 'wb-breadcrumbs';
+import { WBManifestReader } from 'wb-collection-manifest';
+import makeArvadosRequest from 'make-arvados-request';
+
+class WBCollectionContent extends Component {
+ constructor(...args) {
+ super(...args);
+ this.state.path = '.';
+ this.state.rows = [];
+ this.state.manifestReader = null;
+ }
+
+ componentDidMount() {
+ let { arvHost, arvToken } = this.props.app.state;
+ let { uuid } = this.props;
+
+ let select = [ 'manifest_text' ];
+ let prom = makeArvadosRequest(arvHost, arvToken,
+ '/arvados/v1/collections/' + uuid +
+ '?select=' + encodeURIComponent(JSON.stringify(select)));
+ prom = prom.then(xhr => {
+ this.state.manifestReader = new WBManifestReader(xhr.response.manifest_text);
+ this.prepareRows();
+ });
+ }
+
+ prepareRows() {
+ this.setState({});
+ }
+
+ render({}, { rows }) {
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+export default WBCollectionContent;
diff --git a/frontend/src/js/misc/wb-arvados-collection.js b/frontend/src/js/misc/wb-arvados-collection.js
index 751a19a..430376c 100644
--- a/frontend/src/js/misc/wb-arvados-collection.js
+++ b/frontend/src/js/misc/wb-arvados-collection.js
@@ -42,7 +42,7 @@ class WBArvadosCollection {
fileSizes = fileNames.map(n => fileSizes[n]);
return [ streamName, fileNames, fileSizes ];
});
-
+
return this.content;
}
}
diff --git a/frontend/src/js/misc/wb-collection-manifest.js b/frontend/src/js/misc/wb-collection-manifest.js
new file mode 100644
index 0000000..704cc9d
--- /dev/null
+++ b/frontend/src/js/misc/wb-collection-manifest.js
@@ -0,0 +1,114 @@
+class CMDirectory {
+ constructor() {
+ this.directories = {};
+ this.files = {};
+ }
+}
+
+class CMFile {
+ constructor() {
+ this.blockRefs = [];
+ this.size = 0;
+ }
+
+ append(locators, position, size) {
+ if (size === 0)
+ return;
+
+ let cum = 0;
+ let locHashes = locators.map(loc => loc[0]);
+ let locSizes = locators.map(loc => loc[1]);
+ let locPositions = locators.map(loc => {
+ let res = cum;
+ cum += loc[1];
+ return res;
+ });
+
+ let used = locators.map((_, i) => (locPositions[i] + locSizes[i] > position &&
+ locPositions[i] < position + size));
+
+ let startBlock = used.indexOf(true);
+ let endBlock = used.lastIndexOf(true) + 1;
+
+ console.log('startBlock: ' + startBlock + ', endBlock: ' + endBlock);
+
+ if (startBlock === -1)
+ return;
+
+ let blockRefs = [];
+ let runPos = position;
+ let runSize = size;
+
+ for (let i = startBlock; i < endBlock; i++) {
+ let blockPos = runPos - locPositions[i];
+ let blockSize = Math.min(runSize, locSizes[i] - blockPos);
+ blockRefs.push([ locHashes[i], blockPos, blockSize ]);
+ runPos += blockSize;
+ runSize -= blockSize;
+ }
+
+ this.blockRefs = this.blockRefs.concat(blockRefs);
+ this.size += size;
+ }
+}
+
+class WBManifestReader {
+ constructor(manifest_text) {
+ this.rootDir = new CMDirectory();
+
+ if (!manifest_text)
+ return;
+
+ this.parse(manifest_text);
+ }
+
+ makeDir(parent, name) {
+ if (!(name in parent.directories))
+ parent.directories[name] = new CMDirectory();
+ return parent.directories[name];
+ }
+
+ makePath(path) {
+ if (typeof(path) === 'string')
+ path = path.split('/');
+ let dir = this.rootDir;
+ for (let i = 1; i < path.length; i++)
+ dir = this.makeDir(dir, path[i]);
+ return dir;
+ }
+
+ appendFile(streamName, locators, position, size, fileName) {
+ let path = streamName + '/' + fileName;
+ path = path.split('/');
+ let dir = this.makePath(path.slice(0, path.length - 1));
+ if (!(fileName in dir.files))
+ dir.files[fileName] = new CMFile();
+ dir.files[fileName].append(locators, position, size);
+ }
+
+ parse(manifest_text) {
+ let rx = /^[a-f0-9]{32}\+[0-9]+/;
+
+ let streams = manifest_text.split('\n');
+
+ streams.map(s => {
+ let tokens = s.split(' ');
+ let streamName = tokens[0];
+
+ let n = tokens.map(t => rx.exec(t));
+ n = n.indexOf(null, 1);
+
+ let locators = tokens.slice(1, n);
+ locators = locators.map(loc => [ loc, Number(loc.split('+')[1]) ]);
+
+ let fileTokens = tokens.slice(n);
+ fileTokens.map(t => {
+ let [ position, size, fileName ] = t.split(':');
+ this.appendFile(streamName, locators,
+ Number(position), Number(size), fileName);
+ });
+ });
+ }
+}
+
+export { WBManifestReader };
diff --git a/frontend/src/js/page/wb-app.js b/frontend/src/js/page/wb-app.js
index 75fda85..ea554fb 100644
--- a/frontend/src/js/page/wb-app.js
+++ b/frontend/src/js/page/wb-app.js
@@ -5,6 +5,7 @@ import WBSignIn from 'wb-sign-in';
import WBLandingPage from 'wb-landing-page';
import WBProcessView from 'wb-process-view';
import WBCollectionView from 'wb-collection-view';
+import WBCollectionBrowse from 'wb-collection-browse';
import arvadosTypeName from 'arvados-type-name';
class WBApp extends Component {
@@ -65,6 +66,8 @@ class WBApp extends Component {
+
+
);
}
diff --git a/frontend/src/js/page/wb-collection-browse.js b/frontend/src/js/page/wb-collection-browse.js
new file mode 100644
index 0000000..e238702
--- /dev/null
+++ b/frontend/src/js/page/wb-collection-browse.js
@@ -0,0 +1,24 @@
+import { h, Component } from 'preact';
+import WBNavbarCommon from 'wb-navbar-common';
+import WBArvadosCrumbs from 'wb-arvados-crumbs';
+import WBCollectionContent from 'wb-collection-content';
+
+class WBCollectionBrowse extends Component {
+ render({ app, uuid }, {}) {
+ return (
+
+
+
+
+
+
+ This is the collection browser for { uuid }
+
+
+
+
+ );
+ }
+}
+
+export default WBCollectionBrowse;