From 1aa0e39e73f1ce08f72011ef05e5c330b390fa9e Mon Sep 17 00:00:00 2001 From: Stanislaw Adaszewski Date: Mon, 3 Feb 2020 07:24:36 +0100 Subject: [PATCH] Started implementing WBCollectionBrowse. --- .../src/js/component/wb-collection-content.js | 45 +++++++ frontend/src/js/misc/wb-arvados-collection.js | 2 +- .../src/js/misc/wb-collection-manifest.js | 114 ++++++++++++++++++ frontend/src/js/page/wb-app.js | 3 + frontend/src/js/page/wb-collection-browse.js | 24 ++++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 frontend/src/js/component/wb-collection-content.js create mode 100644 frontend/src/js/misc/wb-collection-manifest.js create mode 100644 frontend/src/js/page/wb-collection-browse.js 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;