@@ -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 ( | |||
<div> | |||
<WBBreadcrumbs items={ [ 'a', 'b', 'c' ] } /> | |||
<WBTable columns={ [ 'Name', 'Size', 'Actions' ] } | |||
rows={ rows } /> | |||
</div> | |||
); | |||
} | |||
} | |||
export default WBCollectionContent; |
@@ -42,7 +42,7 @@ class WBArvadosCollection { | |||
fileSizes = fileNames.map(n => fileSizes[n]); | |||
return [ streamName, fileNames, fileSizes ]; | |||
}); | |||
return this.content; | |||
} | |||
} | |||
@@ -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 }; |
@@ -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 { | |||
<WBProcessView path="/process/:uuid" app={ this } /> | |||
<WBCollectionView path="/collection/:uuid" app={ this } /> | |||
<WBCollectionBrowse path='/collection-browse/:uuid' app={ this } /> | |||
</Router> | |||
); | |||
} | |||
@@ -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 ( | |||
<div> | |||
<WBNavbarCommon app={ app } /> | |||
<WBArvadosCrumbs app={ app } uuid={ uuid } /> | |||
<div class="my-2"> | |||
This is the collection browser for { uuid } | |||
</div> | |||
<WBCollectionContent app={ app } uuid={ uuid } /> | |||
</div> | |||
); | |||
} | |||
} | |||
export default WBCollectionBrowse; |