| @@ -2,6 +2,9 @@ | |||||
| function makeArvadosRequest(arvHost, arvToken, endpoint, method='GET', data=null, | function makeArvadosRequest(arvHost, arvToken, endpoint, method='GET', data=null, | ||||
| contentType='application/json;charset=utf-8', responseType='json') { | contentType='application/json;charset=utf-8', responseType='json') { | ||||
| if (!arvHost || !arvToken) | |||||
| return new Promise((accept, reject) => reject()); | |||||
| let xhr = new XMLHttpRequest(); | let xhr = new XMLHttpRequest(); | ||||
| xhr.open(method, 'https://' + arvHost + endpoint); | xhr.open(method, 'https://' + arvHost + endpoint); | ||||
| xhr.setRequestHeader('Authorization', 'OAuth2 ' + arvToken); | xhr.setRequestHeader('Authorization', 'OAuth2 ' + arvToken); | ||||
| @@ -1,24 +1,36 @@ | |||||
| import { h, Component } from 'preact'; | import { h, Component } from 'preact'; | ||||
| import { Router, route } from 'preact-router'; | import { Router, route } from 'preact-router'; | ||||
| import WBTabs from 'wb-tabs'; | |||||
| import WBTable from 'wb-table'; | |||||
| import WBPagination from 'wb-pagination'; | |||||
| import WBProjectListing from 'wb-project-listing'; | |||||
| import WBNavbar from 'wb-navbar'; | |||||
| import WBBrowse from 'wb-browse'; | import WBBrowse from 'wb-browse'; | ||||
| import WBSignIn from 'wb-sign-in'; | import WBSignIn from 'wb-sign-in'; | ||||
| import WBLandingPage from 'wb-landing-page'; | |||||
| class WBApp extends Component { | class WBApp extends Component { | ||||
| render({}, { activePage }) { | |||||
| constructor(...args) { | |||||
| super(...args); | |||||
| this.state.arvHost = window.localStorage['arvHost']; | |||||
| this.state.arvToken = window.localStorage['arvToken']; | |||||
| this.appCallbacks = { | |||||
| 'navbarItemClicked': this.navbarItemClicked | |||||
| }; | |||||
| } | |||||
| navbarItemClicked(item) { | |||||
| if (item['id'] === 'sign-out') { | |||||
| delete window.localStorage['arvHost']; | |||||
| delete window.localStorage['arvToken']; | |||||
| delete window.localStorage['currentUser']; | |||||
| route('/sign-in'); | |||||
| } | |||||
| } | |||||
| render({}, { activePage, arvHost, arvToken }) { | |||||
| return ( | return ( | ||||
| <Router> | <Router> | ||||
| <div path="/"> | |||||
| Hello, world! | |||||
| </div> | |||||
| <WBLandingPage path="/" /> | |||||
| <WBSignIn path="/sign-in" /> | <WBSignIn path="/sign-in" /> | ||||
| <WBBrowse path="/browse/:ownerUuid?" /> | |||||
| <WBBrowse path="/browse/:ownerUuid?" appCallbacks={ this.appCallbacks } /> | |||||
| </Router> | </Router> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -4,15 +4,16 @@ import WBProjectListing from 'wb-project-listing'; | |||||
| import WBInlineSearch from 'wb-inline-search'; | import WBInlineSearch from 'wb-inline-search'; | ||||
| class WBBrowse extends Component { | class WBBrowse extends Component { | ||||
| render({ ownerUuid }) { | |||||
| render({ ownerUuid, appCallbacks }) { | |||||
| return ( | return ( | ||||
| <div> | <div> | ||||
| <WBNavbar items={ [ | <WBNavbar items={ [ | ||||
| { 'name': 'Browse', 'active': true }, | { 'name': 'Browse', 'active': true }, | ||||
| { 'name': 'User', 'dropdown': [ 'Sign Off' ]} | |||||
| { 'name': 'User', 'dropdown': [ { 'id': 'sign-out', 'name': 'Sign Out' } ]} | |||||
| ] } rhs={ ( | ] } rhs={ ( | ||||
| <WBInlineSearch /> | <WBInlineSearch /> | ||||
| ) } /> | |||||
| ) } onItemClicked={ appCallbacks.navbarItemClicked } /> | |||||
| <WBProjectListing arvHost="api.arkau.roche.com" | <WBProjectListing arvHost="api.arkau.roche.com" | ||||
| arvToken="v2/arkau-gj3su-uf4hnu2o2qkvm8j/15kla38mafzq6b31d5t74ynhk6iuy32v1ticslodr0obvvhde9" | arvToken="v2/arkau-gj3su-uf4hnu2o2qkvm8j/15kla38mafzq6b31d5t74ynhk6iuy32v1ticslodr0obvvhde9" | ||||
| ownerUuid={ ownerUuid } | ownerUuid={ ownerUuid } | ||||
| @@ -0,0 +1,20 @@ | |||||
| import { h, Component } from 'preact'; | |||||
| import makeArvadosRequest from 'make-arvados-request'; | |||||
| import { route } from 'preact-router'; | |||||
| class WBLandingPage extends Component { | |||||
| componentDidMount() { | |||||
| let { arvHost, arvToken } = window.localStorage; | |||||
| let prom = makeArvadosRequest(arvHost, arvToken, '/arvados/v1/users/current'); | |||||
| prom = prom.then(xhr => route('/browse/' + xhr.response['uuid'])); | |||||
| prom = prom.catch(() => route('/sign-in')); | |||||
| } | |||||
| render() { | |||||
| return ( | |||||
| <div>Please wait...</div> | |||||
| ); | |||||
| } | |||||
| } | |||||
| export default WBLandingPage; | |||||
| @@ -1,24 +1,49 @@ | |||||
| import { h, Component } from 'preact'; | import { h, Component } from 'preact'; | ||||
| import { route } from 'preact-router'; | |||||
| import WBNavbar from 'wb-navbar'; | import WBNavbar from 'wb-navbar'; | ||||
| import linkState from 'linkstate'; | |||||
| import makeArvadosRequest from 'make-arvados-request'; | |||||
| class WBLogin extends Component { | |||||
| render() { | |||||
| class WBSignIn extends Component { | |||||
| onSubmit() { | |||||
| let { arvHost, arvToken } = this.state; | |||||
| window.localStorage['arvHost'] = arvHost; | |||||
| window.localStorage['arvToken'] = arvToken; | |||||
| let prom = makeArvadosRequest(arvHost, arvToken, '/arvados/v1/users/current'); | |||||
| prom = prom.then(xhr => { | |||||
| window.localStorage['currentUser'] = JSON.stringify(xhr.response); | |||||
| route('/browse/' + xhr.response['uuid']); | |||||
| }); | |||||
| prom = prom.catch(() => { | |||||
| alert('Sign in unsuccessful. Verify your input and try again.') | |||||
| }); | |||||
| } | |||||
| render({}, { arvHost, arvToken }) { | |||||
| return ( | return ( | ||||
| <div> | <div> | ||||
| <div class="container"> | |||||
| <WBNavbar /> | |||||
| <div class="container my-3"> | |||||
| <div class="row justify-content-center"> | <div class="row justify-content-center"> | ||||
| <div class="col-6"> | <div class="col-6"> | ||||
| <h1>Sign In</h1> | <h1>Sign In</h1> | ||||
| <form> | <form> | ||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label for="arvHost">Arvados API Host</label> | <label for="arvHost">Arvados API Host</label> | ||||
| <input type="text" class="form-control" id="arvHost" placeholder="Enter Arvados API Host" /> | |||||
| <input type="text" class="form-control" id="arvHost" | |||||
| placeholder="Enter Arvados API Host" | |||||
| value={ arvHost } | |||||
| onInput={ linkState(this, 'arvHost') } /> | |||||
| </div> | </div> | ||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label for="arvToken">Token</label> | <label for="arvToken">Token</label> | ||||
| <input type="text" class="form-control" id="arvToken" placeholder="Enter Arvados API Token" /> | |||||
| <input type="text" class="form-control" id="arvToken" | |||||
| placeholder="Enter Arvados API Token" | |||||
| value={ arvToken } | |||||
| onInput={ linkState(this, 'arvToken') } /> | |||||
| </div> | </div> | ||||
| <button type="submit" class="btn btn-primary">Submit</button> | |||||
| <button type="submit" class="btn btn-primary" | |||||
| onclick={ e => { e.preventDefault(); this.onSubmit(); } }>Submit</button> | |||||
| </form> | </form> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -28,4 +53,4 @@ class WBLogin extends Component { | |||||
| } | } | ||||
| } | } | ||||
| export default WBLogin; | |||||
| export default WBSignIn; | |||||
| @@ -1,10 +1,10 @@ | |||||
| import { h, Component } from 'preact'; | import { h, Component } from 'preact'; | ||||
| class WBNavbar extends Component { | class WBNavbar extends Component { | ||||
| render({ title, items, rhs, onItemClicked }) { | |||||
| render({ title, items, rhs, onItemClicked, onTitleClicked }) { | |||||
| return ( | return ( | ||||
| <nav class="navbar navbar-expand-lg navbar-light bg-light"> | <nav class="navbar navbar-expand-lg navbar-light bg-light"> | ||||
| <a class="navbar-brand" href="#">{ title }</a> | |||||
| <a class="navbar-brand" href="#" onclick={ e => { e.preventDefault(); onTitleClicked(); } }>{ title }</a> | |||||
| <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> | <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> | ||||
| <span class="navbar-toggler-icon"></span> | <span class="navbar-toggler-icon"></span> | ||||
| @@ -52,6 +52,11 @@ class WBNavbar extends Component { | |||||
| return ( | return ( | ||||
| <div class="dropdown-divider" /> | <div class="dropdown-divider" /> | ||||
| ); | ); | ||||
| else if (typeof(d) === 'object' && d['name']) | |||||
| return ( | |||||
| <a class="dropdown-item" href="#" onclick={ e => { e.preventDefault(); onItemClicked(d); } }>{ d['name'] }</a> | |||||
| ); | |||||
| }) } | }) } | ||||
| </div> | </div> | ||||
| </li> | </li> | ||||
| @@ -81,7 +86,8 @@ WBNavbar.defaultProps = { | |||||
| 'title': 'Workbench Advanced', | 'title': 'Workbench Advanced', | ||||
| 'items': [], | 'items': [], | ||||
| 'form': null, | 'form': null, | ||||
| 'onItemClicked': () => {} | |||||
| 'onItemClicked': () => {}, | |||||
| 'onTitleClicked': () => {} | |||||
| } | } | ||||
| export default WBNavbar; | export default WBNavbar; | ||||