@@ -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; |