| @@ -1,11 +1,72 @@ | |||
| import { h, Component } from 'preact'; | |||
| import WBTable from 'wb-table'; | |||
| import WBPagination from 'wb-pagination'; | |||
| import makeArvadosRequest from 'make-arvados-request'; | |||
| class WBBrowseDialogCollectionList extends Component { | |||
| render() { | |||
| constructor(...args) { | |||
| super(...args); | |||
| this.state.rows = []; | |||
| } | |||
| componentDidMount() { | |||
| this.fetchRows(); | |||
| } | |||
| componentWillReceiveProps(nextProps) { | |||
| this.props = nextProps; | |||
| this.fetchRows(); | |||
| } | |||
| prepareRows(items) { | |||
| const { navigate, selectWhat, makeSelectionCell } = this.props; | |||
| return items.map(it => (selectWhat === 'directory' ? [ | |||
| makeSelectionCell(it.uuid) | |||
| ] : []).concat([ | |||
| ( | |||
| <a href="#" onclick={ e => { e.preventDefault(); | |||
| navigate('/browse-dialog/content/' + it.uuid); } }>{ it.name }</a> | |||
| ), | |||
| it.uuid | |||
| ])); | |||
| } | |||
| fetchRows() { | |||
| const { arvHost, arvToken } = this.props.app.state; | |||
| const { ownerUuid, textSearch, page, itemsPerPage } = this.props; | |||
| const filters = []; | |||
| if (ownerUuid) | |||
| filters.push(['owner_uuid', '=', ownerUuid]); | |||
| if (textSearch) | |||
| filters.push(['name', 'ilike', '%' + textSearch + '%']); | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/collections?filters=' + | |||
| encodeURIComponent(JSON.stringify(filters)) + | |||
| '&limit=' + itemsPerPage + | |||
| '&offset=' + (itemsPerPage * page)); | |||
| prom = prom.then(xhr => this.setState({ | |||
| 'rows': this.prepareRows(xhr.response.items), | |||
| 'numPages': Math.ceil(xhr.response.items_available / itemsPerPage) | |||
| })); | |||
| return prom; | |||
| } | |||
| render({ selectWhat, page, navigate }, { rows, numPages }) { | |||
| return ( | |||
| <div>WBBrowseDialogCollectionList</div> | |||
| <div> | |||
| <WBTable columns={ (selectWhat === 'directory' ? [''] : []).concat(['Name', 'UUID']) } | |||
| headerClasses={ selectWhat === 'directory' ? ['col-sm-1', 'col-sm-4', 'col-sm-4'] : [] } | |||
| rows={ rows } /> | |||
| <WBPagination activePage={ page } numPages={ numPages } | |||
| onPageChanged={ i => navigate({ 'bottomPage': i }) } /> | |||
| </div> | |||
| ); | |||
| } | |||
| } | |||
| WBBrowseDialogCollectionList.defaultProps = { | |||
| 'itemsPerPage': 20 | |||
| }; | |||
| export default WBBrowseDialogCollectionList; | |||
| @@ -20,8 +20,8 @@ class WBBrowseDialogProjectList extends Component { | |||
| } | |||
| prepareRows(items) { | |||
| const { navigate } = this.props; | |||
| return items.map(it => [ | |||
| const { navigate, selectWhat, makeSelectionCell } = this.props; | |||
| return items.map(it => (selectWhat === 'owner' ? [ makeSelectionCell(it.uuid, 'project') ] : []).concat([ | |||
| ( | |||
| <a href="#" onclick={ e => { | |||
| e.preventDefault(); | |||
| @@ -29,7 +29,7 @@ class WBBrowseDialogProjectList extends Component { | |||
| } }>{ it.name }</a> | |||
| ), | |||
| it.uuid | |||
| ]); | |||
| ])); | |||
| } | |||
| fetchSharedWithMe() { | |||
| @@ -83,10 +83,11 @@ class WBBrowseDialogProjectList extends Component { | |||
| return prom; | |||
| } | |||
| render({ app, navigate, page }, { numPages, rows }) { | |||
| render({ app, navigate, page, selectWhat }, { numPages, rows }) { | |||
| return ( | |||
| <div> | |||
| <WBTable columns={ ['Name', 'UUID'] } | |||
| <WBTable columns={ (selectWhat === 'owner' ? [''] : []).concat(['Name', 'UUID']) } | |||
| headerClasses={ selectWhat === 'owner' ? ['col-sm-1', 'col-sm-4', 'col-sm-4'] : [] } | |||
| rows={ rows } /> | |||
| <WBPagination numPages={ numPages } activePage={ page } | |||
| @@ -41,6 +41,8 @@ class WBBrowseDialogUserList extends Component { | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/users?order=' + | |||
| encodeURIComponent(JSON.stringify(order)) + | |||
| '&filters=' + | |||
| encodeURIComponent(JSON.stringify(filters)) + | |||
| '&limit=' + itemsPerPage + | |||
| '&offset=' + (itemsPerPage * page)); | |||
| prom = prom.then(xhr => this.setState({ | |||
| @@ -105,6 +105,31 @@ class WBBrowseDialog extends Component { | |||
| }); | |||
| } | |||
| makeSelectionCell(uuid) { | |||
| const { selectMany, id, accept } = this.props; | |||
| const { selected } = this.state; | |||
| return selectMany ? ( | |||
| <div> | |||
| <input type="checkbox" checked={ (uuid in selected) } | |||
| onChange={ e => { | |||
| if (e.target.value === 'on') | |||
| this.select(uuid); | |||
| else | |||
| this.deselect(uuid); | |||
| } } /> { '\u00A0' } | |||
| </div> | |||
| ) : ( | |||
| <button class="btn btn-outline-primary" title="Use" | |||
| onclick={ () => { | |||
| $('#' + id).modal('hide'); | |||
| accept(uuid); | |||
| } }> | |||
| <i class="fas fa-hand-pointer"></i> | |||
| </button> | |||
| ); | |||
| } | |||
| render({ app, id, selectMany, selectWhat }, { history, currentUrl, mode, uuid, topPage, bottomPage, textSearch }) { | |||
| return ( | |||
| <div class="modal" id={ id } tabindex="-1" role="dialog"> | |||
| @@ -141,7 +166,7 @@ class WBBrowseDialog extends Component { | |||
| <div class="input-group mb-3"> | |||
| <input type="text" class="form-control" placeholder="Search" | |||
| aria-label="Search" value={ textSearch } | |||
| onChange={ e => this.setState({ | |||
| onChange={ e => this.navigate({ | |||
| 'textSearch': e.target.value, | |||
| 'topPage': 0, | |||
| 'bottomPage': 0}) } /> | |||
| @@ -157,7 +182,9 @@ class WBBrowseDialog extends Component { | |||
| <WBBrowseDialogProjectList app={ app } | |||
| navigate={ url => this.navigate(url) } | |||
| mode={ mode } ownerUuid={ uuid } | |||
| page={ topPage } textSearch={ textSearch } /> | |||
| page={ topPage } textSearch={ textSearch } | |||
| selectWhat={ selectWhat } | |||
| makeSelectionCell={ uuid => this.makeSelectionCell(uuid) } /> | |||
| </div> | |||
| ) : null } | |||
| @@ -174,11 +201,14 @@ class WBBrowseDialog extends Component { | |||
| selectMany={ selectMany } selectWhat={ selectWhat }/> | |||
| </div> | |||
| ) : (mode === 'browse' || mode === 'shared-with-me') ? ( | |||
| ) : (selectWhat !== 'owner' && mode === 'browse') ? ( | |||
| <div> | |||
| <h5>Collections</h5> | |||
| <WBBrowseDialogCollectionList app={ app } parent={ this } | |||
| selectMany={ selectMany } selectWhat={ selectWhat } /> | |||
| <WBBrowseDialogCollectionList app={ app } | |||
| page={ bottomPage } textSearch={ textSearch } | |||
| navigate={ url => this.navigate(url) } | |||
| ownerUuid={ uuid } selectWhat={ selectWhat } | |||
| makeSelectionCell={ uuid => this.makeSelectionCell(uuid) } /> | |||
| </div> | |||
| ) : null } | |||
| </div> | |||
| @@ -194,4 +224,8 @@ class WBBrowseDialog extends Component { | |||
| } | |||
| } | |||
| WBBrowseDialog.defaultProps = { | |||
| 'accept': () => {} | |||
| }; | |||
| export default WBBrowseDialog; | |||
| @@ -110,7 +110,8 @@ class WBLaunchWorkflowPage extends Component { | |||
| items={ app.state.toolboxItems } selectMany={ true } | |||
| onAccepted={ values => alert(values) } /> | |||
| <WBBrowseDialog app={ app } id={ realBrowseDialogId } /> | |||
| <WBBrowseDialog app={ app } id={ realBrowseDialogId } | |||
| selectWhat="directory" /> | |||
| { workflow ? | |||
| (<form class="container-fluid"> | |||