IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
4.5KB

  1. //
  2. // Copyright (C) Stanislaw Adaszewski, 2020
  3. // Contact: s.adaszewski@gmail.com
  4. // Website: https://adared.ch/wba
  5. // License: GNU Affero General Public License, Version 3
  6. //
  7. import { h, Component } from 'preact';
  8. import WBManifestWorkerWrapper from 'wb-manifest-worker-wrapper';
  9. import makeArvadosRequest from 'make-arvados-request';
  10. import WBTable from 'wb-table';
  11. import WBPagination from 'wb-pagination';
  12. function unescapeName(name) {
  13. return name.replace(/(\\\\|\\[0-9]{3})/g,
  14. (_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8))));
  15. }
  16. class WBBrowseDialogCollectionContent extends Component {
  17. constructor(...args) {
  18. super(...args);
  19. this.state.manifestWorker = new WBManifestWorkerWrapper();
  20. this.state.mode = 'manifestDownload';
  21. this.state.rows = [];
  22. }
  23. componentDidMount() {
  24. const { app, collectionUuid } = this.props;
  25. const { arvHost, arvToken } = app.state;
  26. const { manifestWorker } = this.state;
  27. let prom = makeArvadosRequest(arvHost, arvToken,
  28. '/arvados/v1/collections/' + collectionUuid);
  29. let streams;
  30. prom = prom.then(xhr => {
  31. streams = xhr.response.manifest_text.split('\n');
  32. const paths = streams.filter(s => s).map(s => {
  33. const n = s.indexOf(' ');
  34. return unescapeName(s.substr(0, n));
  35. });
  36. return manifestWorker.postMessage([ 'precreatePaths', paths ]);
  37. });
  38. prom = prom.then(() => {
  39. this.setState({ 'mode': 'manifestParse' });
  40. let prom_1 = new Promise(accept => accept());
  41. for (let i = 0; i < streams.length; i++) {
  42. prom_1 = prom_1.then(() => manifestWorker.postMessage([ 'parseStream', streams[i] ]));
  43. prom_1 = prom_1.then(() => manifestWorker.postMessage([ 'listDirectory', '.' + this.props.collectionPath, true ]));
  44. prom_1 = prom_1.then(e => this.prepareRows(e.data[1]));
  45. }
  46. return prom_1;
  47. });
  48. prom = prom.then(() => manifestWorker.postMessage([ 'listDirectory', '.' + this.props.collectionPath, true ]));
  49. prom = prom.then(e => {
  50. this.state.mode = 'browsingReady';
  51. this.prepareRows(e.data[1])
  52. });
  53. }
  54. componentWillReceiveProps(nextProps) {
  55. this.props = nextProps;
  56. if (this.state.mode !== 'browsingReady')
  57. return;
  58. let prom = this.state.manifestWorker.postMessage([
  59. 'listDirectory', '.' + this.props.collectionPath, true
  60. ]);
  61. prom = prom.then(e => this.prepareRows(e.data[1]));
  62. }
  63. prepareRows(listing) {
  64. const { makeSelectionCell, collectionPath, navigate,
  65. page, itemsPerPage, collectionUuid, textSearch, selectWhat } = this.props;
  66. const textLower = textSearch.toLowerCase();
  67. listing = listing.filter(it => (it[1].toLowerCase().indexOf(textLower) !== -1));
  68. const numPages = Math.ceil(listing.length / itemsPerPage);
  69. const rows = listing.slice(page * itemsPerPage,
  70. (page + 1) * itemsPerPage).map(it => [
  71. ((it[0] === 'd' && [].concat(selectWhat).indexOf('directory') !== -1) ||
  72. (it[0] === 'f' && [].concat(selectWhat).indexOf('file') !== -1)) ?
  73. makeSelectionCell(collectionUuid + collectionPath + '/' + it[1] + (it[0] === 'd' ? '/' : '')) :
  74. null,
  75. it[0] === 'd' ? (
  76. <a href="#" onclick={ e => {
  77. e.preventDefault();
  78. navigate({ 'collectionPath': collectionPath + '/' + it[1],
  79. 'bottomPage': 0 });
  80. } }>{ it[1] }</a>
  81. ) : it[1],
  82. it[0] === 'f' ? filesize(it[2]) : ''
  83. ]);
  84. this.setState({ rows, numPages });
  85. }
  86. render({ page, navigate }, { rows, mode, numPages }) {
  87. return (
  88. <div>
  89. { mode === 'browsingReady' ? (
  90. null
  91. ) : [
  92. <div>{ mode === 'manifestParse' ? 'Parsing manifest...' : 'Downloading manifest...' }</div>,
  93. <div class="progress my-2">
  94. <div class={ 'progress-bar progress-bar-striped progress-bar-animated' +
  95. (mode === 'manifestParse' ? ' bg-success': '') } role="progressbar"
  96. aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
  97. </div>
  98. ] }
  99. <WBTable headerClasses={ [ 'w-1' ] }
  100. columns={ [ '', 'Name', 'Size' ] } rows={ rows } />
  101. <WBPagination numPages={ numPages } activePage={ page }
  102. onPageChanged={ i => navigate({ 'bottomPage': i }) } />
  103. </div>
  104. );
  105. }
  106. }
  107. WBBrowseDialogCollectionContent.defaultProps = {
  108. 'itemsPerPage': 20
  109. };
  110. export default WBBrowseDialogCollectionContent;