| @@ -23,6 +23,7 @@ export default { | |||||
| 'src/css/index.css': 'dist/css/index.css', | 'src/css/index.css': 'dist/css/index.css', | ||||
| 'node_modules/bootstrap/dist/css/bootstrap.min.css': 'dist/css/bootstrap.min.css', | 'node_modules/bootstrap/dist/css/bootstrap.min.css': 'dist/css/bootstrap.min.css', | ||||
| 'node_modules/bootstrap/dist/js/bootstrap.min.js': 'dist/js/bootstrap.min.js', | 'node_modules/bootstrap/dist/js/bootstrap.min.js': 'dist/js/bootstrap.min.js', | ||||
| 'node_modules/jquery/dist/jquery.min.js': 'dist/js/jquery.min.js', | |||||
| verbose: true | verbose: true | ||||
| }), | }), | ||||
| buble({jsx: 'h'}), | buble({jsx: 'h'}), | ||||
| @@ -2,6 +2,7 @@ | |||||
| <head> | <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||||
| <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css" /> | <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css" /> | ||||
| <script language="javascript" src="/js/jquery.min.js"></script> | |||||
| <script language="javascript" src="/js/bootstrap.min.js"></script> | <script language="javascript" src="/js/bootstrap.min.js"></script> | ||||
| </head> | </head> | ||||
| <body> | <body> | ||||
| @@ -1,37 +1,24 @@ | |||||
| import { h, Component } from 'preact'; | import { h, Component } from 'preact'; | ||||
| import WBTabs from 'wb-tabs'; | import WBTabs from 'wb-tabs'; | ||||
| import WBTable from 'wb-table'; | |||||
| import WBPagination from 'wb-pagination'; | |||||
| class WBApp extends Component { | class WBApp extends Component { | ||||
| render() { | render() { | ||||
| return ( | return ( | ||||
| <div> | <div> | ||||
| <h1>WBApp</h1> | <h1>WBApp</h1> | ||||
| <table class="table table-striped table-hover"> | |||||
| <thead class="thead-light"> | |||||
| <tr> | |||||
| <th>Name</th> | |||||
| <th>Description</th> | |||||
| <th>Size</th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <tr> | |||||
| <td>Name</td> | |||||
| <td>Description</td> | |||||
| <td>0 bytes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>Name</td> | |||||
| <td>Description</td> | |||||
| <td>0 bytes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>Name</td> | |||||
| <td>Description</td> | |||||
| <td>0 bytes</td> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| <WBPagination numPages={ 100 } activePage={ 0 } | |||||
| onPageChanged={ idx => alert(idx) } /> | |||||
| <WBTable | |||||
| columns={ [ 'Name', 'Description', 'Size' ] } | |||||
| rows={ [ | |||||
| [ 'Name', 'Description', '0 bytes'], | |||||
| [ 'Name', 'Description', '0 bytes'], | |||||
| [ 'Name', 'Description', '0 bytes'], | |||||
| [ 'Name', 'Description', '0 bytes'], | |||||
| [ 'Name', 'Description', '0 bytes'] | |||||
| ] } /> | |||||
| <WBTabs tabs={ [ | <WBTabs tabs={ [ | ||||
| { 'name': 'Ala', 'isActive': true }, | { 'name': 'Ala', 'isActive': true }, | ||||
| "Ma", | "Ma", | ||||
| @@ -0,0 +1,20 @@ | |||||
| import { h, Component } from 'preact'; | |||||
| import makeArvadosRequest from 'make-arvados-request'; | |||||
| class WBProjectListing extends Component { | |||||
| componentDidMount() { | |||||
| let filters = [ | |||||
| [ 'group_class', '=', 'project' ], | |||||
| [ 'owner_uuid', '=', this.props.ownerUuid ] | |||||
| ]; | |||||
| let req = makeArvadosRequest(his.props.arvHost, this.props.arvToken, | |||||
| '/arvados/v1/groups?filters=' + encodeURIComponent(JSON.stringify(filters))) | |||||
| } | |||||
| render({ arvHost, arvToken, ownerUuid }) { | |||||
| return ( | |||||
| <div>Project Listing</div> | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| makeArvadosRequest(arvHost, arvToken, endpoint, method='GET', data=null, | |||||
| contentType='application/json;charset=utf-8', responseType='json') { | |||||
| let xhr = new XMLHttpRequest(); | |||||
| xhr.open(method, 'https://' + arvHost + endpoint); | |||||
| xhr.setRequestHeader('Authorization', 'OAuth2 ' + arvToken); | |||||
| if (data !== null) | |||||
| xhr.setRequestHeader('Content-Type', contentType); | |||||
| xhr.responseType = responseType; | |||||
| let res = new Promise((accept, reject) => { | |||||
| xhr.onreadystatechange = () => { | |||||
| if (xhr.readyState !== 4) | |||||
| return; | |||||
| if (xhr.status !== 200) | |||||
| reject(xhr); | |||||
| else | |||||
| accept(xhr); | |||||
| }; | |||||
| xhr.send(data); | |||||
| }); | |||||
| return res; | |||||
| } | |||||
| export default makeArvadosRequest; | |||||
| @@ -0,0 +1,73 @@ | |||||
| import { h, Component } from 'preact'; | |||||
| class WBPagination extends Component { | |||||
| renderVisiblePages(numPages, activePage, chunkSize, onPageChanged) { | |||||
| let visible = {}; | |||||
| let begActChnk = activePage - Math.floor(chunkSize / 2); | |||||
| let endActChnk = activePage + Math.floor(chunkSize / 2) + 1; | |||||
| for (let i = begActChnk; i < endActChnk; i++) | |||||
| visible[i] = true; | |||||
| for (let i = 0; i < chunkSize; i++) | |||||
| visible[i] = true; | |||||
| for (let i = Math.max(numPages - chunkSize, 0); i < numPages; i++) | |||||
| visible[i] = true; | |||||
| visible = Object.keys(visible).map(n => Number(n)); | |||||
| let res = []; | |||||
| let prev = 0; | |||||
| res.push(( | |||||
| <li class={ activePage === 0 ? "page-item disabled" : "page-item" }> | |||||
| <a class="page-link" href="#" | |||||
| onclick={ () => onPageChanged(activePage - 1) }>Previous</a> | |||||
| </li> | |||||
| )); | |||||
| for (let i in visible) { | |||||
| if (i > prev + 1) | |||||
| res.push(( | |||||
| <li class="page-item"> | |||||
| <a class="page-link" href="#" | |||||
| onclick={ () => onPageChanged(i - 1) }>...</a> | |||||
| </li> | |||||
| )); | |||||
| prev = i; | |||||
| res.push(( | |||||
| <li class={ i === activePage ? "page-item active" : "page-item" }> | |||||
| <a class="page-link" href="#" | |||||
| onclick={ () => onPageChanged(i) }>{ i + 1 }</a> | |||||
| </li> | |||||
| )); | |||||
| } | |||||
| res.push(( | |||||
| <li class={ activePage >= numPages - 1 ? "page-item disabled" : "page-item" }> | |||||
| <a class="page-link" href="#" | |||||
| onclick={ () => onPageChanged(activePage + 1) }>Next</a> | |||||
| </li> | |||||
| )); | |||||
| return res; | |||||
| } | |||||
| render({ numPages, activePage, chunkSize, onPageChanged }) { | |||||
| return ( | |||||
| <nav aria-label="Pagination"> | |||||
| <ul class="pagination"> | |||||
| { this.renderVisiblePages(numPages, activePage, chunkSize, onPageChanged) } | |||||
| </ul> | |||||
| </nav> | |||||
| ); | |||||
| } | |||||
| } | |||||
| WBPagination.defaultProps = { | |||||
| 'chunkSize': 5 | |||||
| }; | |||||
| export default WBPagination; | |||||
| @@ -0,0 +1,26 @@ | |||||
| import { h, Component } from 'preact'; | |||||
| class WBTable extends Component { | |||||
| render({ columns, rows }) { | |||||
| return ( | |||||
| <table class="table table-striped table-hover"> | |||||
| <thead class="thead-light"> | |||||
| <tr> | |||||
| { columns.map(c => <th>{ c }</th>) } | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| { rows.map(r => ( | |||||
| <tr> | |||||
| { columns.map((_, idx) => ( | |||||
| <td>{ r[idx] }</td> | |||||
| )) } | |||||
| </tr> | |||||
| )) } | |||||
| </tbody> | |||||
| </table> | |||||
| ); | |||||
| } | |||||
| } | |||||
| export default WBTable; | |||||