mirror of
https://github.com/docker/docs.git
synced 2026-03-27 14:28:47 +07:00
wip
This commit is contained in:
BIN
images/userdropdown@2x.png
Normal file
BIN
images/userdropdown@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 681 B |
@@ -2,7 +2,7 @@ import alt from '../alt';
|
||||
import hub from '../utils/HubUtil';
|
||||
|
||||
class AccountActions {
|
||||
login(username, password) {
|
||||
login (username, password) {
|
||||
this.dispatch({});
|
||||
hub.login(username, password);
|
||||
}
|
||||
@@ -12,8 +12,14 @@ class AccountActions {
|
||||
hub.signup(username, password, email, subscribe);
|
||||
}
|
||||
|
||||
logout () {
|
||||
this.dispatch({});
|
||||
hub.logout();
|
||||
}
|
||||
|
||||
skip () {
|
||||
this.dispatch({});
|
||||
hub.prompted(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,16 @@ import router from '../router';
|
||||
class AccountServerActions {
|
||||
constructor () {
|
||||
this.generateActions(
|
||||
'loggedout',
|
||||
'prompted',
|
||||
'errors'
|
||||
);
|
||||
}
|
||||
|
||||
loggedin ({username, verified}) {
|
||||
console.log(username, verified);
|
||||
router.get().goBack();
|
||||
if (router.get()) {
|
||||
router.get().goBack();
|
||||
}
|
||||
this.dispatch({username, verified});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import alt from '../alt';
|
||||
class RepositoryServerActions {
|
||||
constructor () {
|
||||
this.generateActions(
|
||||
'searched',
|
||||
'fetched',
|
||||
'error'
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ var metrics = require('./utils/MetricsUtil');
|
||||
var router = require('./router');
|
||||
var template = require('./menutemplate');
|
||||
var webUtil = require('./utils/WebUtil');
|
||||
var hubUtil = require('./utils/HubUtil');
|
||||
var urlUtil = require ('./utils/URLUtil');
|
||||
var app = remote.require('app');
|
||||
var request = require('request');
|
||||
@@ -24,6 +25,8 @@ webUtil.addLiveReload();
|
||||
webUtil.addBugReporting();
|
||||
webUtil.disableGlobalBackspace();
|
||||
|
||||
hubUtil.init();
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
|
||||
|
||||
metrics.track('Started App');
|
||||
|
||||
@@ -27,10 +27,10 @@ app.on('open-url', function (event, url) {
|
||||
|
||||
app.on('ready', function () {
|
||||
var mainWindow = new BrowserWindow({
|
||||
width: size.width || 1000,
|
||||
height: size.height || 700,
|
||||
'min-width': 1000,
|
||||
'min-height': 700,
|
||||
width: size.width || 800,
|
||||
height: size.height || 600,
|
||||
'min-width': 800,
|
||||
'min-height': 600,
|
||||
'standard-window': false,
|
||||
resizable: true,
|
||||
frame: false,
|
||||
|
||||
@@ -13,6 +13,16 @@ module.exports = React.createClass({
|
||||
return accountStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
document.addEventListener('keyup', this.handleDocumentKeyUp, false);
|
||||
accountStore.listen(this.update);
|
||||
},
|
||||
|
||||
componentWillUnmount: function () {
|
||||
document.removeEventListener('keyup', this.handleDocumentKeyUp, false);
|
||||
accountStore.unlisten(this.update);
|
||||
},
|
||||
|
||||
handleSkip: function () {
|
||||
accountActions.skip();
|
||||
this.transitionTo('search');
|
||||
@@ -24,17 +34,13 @@ module.exports = React.createClass({
|
||||
metrics.track('Closed Signup');
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
accountStore.listen(this.update);
|
||||
},
|
||||
|
||||
update: function () {
|
||||
this.setState(accountStore.getState());
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let close = this.state.prompted ?
|
||||
<a className="btn btn-action btn-skip" onClick={this.handleClose}>Close</a> :
|
||||
<a className="btn btn-action btn-close" onClick={this.handleClose}>Close</a> :
|
||||
<a className="btn btn-action btn-skip" onClick={this.handleSkip}>Skip For Now</a>;
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,9 @@ module.exports = React.createClass({
|
||||
errors: {}
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
React.findDOMNode(this.refs.usernameInput).focus();
|
||||
},
|
||||
componentWillReceiveProps: function (nextProps) {
|
||||
this.setState({errors: nextProps.errors});
|
||||
},
|
||||
@@ -50,7 +52,7 @@ module.exports = React.createClass({
|
||||
|
||||
handleClickSignup: function () {
|
||||
if (!this.props.loading) {
|
||||
this.transitionTo('signup');
|
||||
this.replaceWith('signup');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -59,11 +61,10 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
render: function () {
|
||||
console.log(this.state.errors);
|
||||
let loading = this.props.loading ? <div className="spinner la-ball-clip-rotate la-dark"><div></div></div> : null;
|
||||
return (
|
||||
<form className="form-connect">
|
||||
<input ref="usernameInput"maxLength="30" name="username" placeholder="username" type="text" disabled={this.props.loading} valueLink={this.linkState('username')} onBlur={this.handleBlur}/>
|
||||
<input ref="usernameInput"maxLength="30" name="username" placeholder="username" type="text" disabled={this.props.loading} valueLink={this.linkState('username')} onBlur={this.handleBlur}/>
|
||||
<p className="error-message">{this.state.errors.username}</p>
|
||||
<input ref="passwordInput" name="password" placeholder="password" type="password" disabled={this.props.loading} valueLink={this.linkState('password')} onBlur={this.handleBlur}/>
|
||||
<p className="error-message">{this.state.errors.password}</p>
|
||||
|
||||
@@ -18,6 +18,10 @@ module.exports = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
React.findDOMNode(this.refs.usernameInput).focus();
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function (nextProps) {
|
||||
this.setState({errors: nextProps.errors});
|
||||
},
|
||||
@@ -54,7 +58,7 @@ module.exports = React.createClass({
|
||||
|
||||
handleClickLogin: function () {
|
||||
if (!this.props.loading) {
|
||||
this.transitionTo('login');
|
||||
this.replaceWith('login');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ var metrics = require('../utils/MetricsUtil');
|
||||
var Menu = remote.require('menu');
|
||||
var MenuItem = remote.require('menu-item');
|
||||
var accountStore = require('../stores/AccountStore');
|
||||
var accountActions = require('../actions/AccountActions');
|
||||
var Router = require('react-router');
|
||||
var classNames = require('classNames');
|
||||
|
||||
var Header = React.createClass({
|
||||
mixins: [Router.Navigation],
|
||||
@@ -23,6 +25,8 @@ var Header = React.createClass({
|
||||
componentDidMount: function () {
|
||||
document.addEventListener('keyup', this.handleDocumentKeyUp, false);
|
||||
|
||||
accountStore.listen(this.update);
|
||||
|
||||
ipc.on('application:update-available', () => {
|
||||
this.setState({
|
||||
updateAvailable: true
|
||||
@@ -32,6 +36,14 @@ var Header = React.createClass({
|
||||
},
|
||||
componentWillUnmount: function () {
|
||||
document.removeEventListener('keyup', this.handleDocumentKeyUp, false);
|
||||
accountStore.unlisten(this.update);
|
||||
},
|
||||
update: function () {
|
||||
let accountState = accountStore.getState();
|
||||
this.setState({
|
||||
username: accountState.username,
|
||||
verified: accountState.verified
|
||||
});
|
||||
},
|
||||
handleDocumentKeyUp: function (e) {
|
||||
if (e.keyCode === 27 && remote.getCurrentWindow().isFullScreen()) {
|
||||
@@ -60,12 +72,15 @@ var Header = React.createClass({
|
||||
},
|
||||
handleUserClick: function (e) {
|
||||
let menu = new Menu();
|
||||
menu.append(new MenuItem({ label: 'Sign Out', click: function() { console.log('item 1 clicked'); } }));
|
||||
menu.append(new MenuItem({ label: 'Sign Out', click: this.handleLogoutClick.bind(this)}));
|
||||
menu.popup(remote.getCurrentWindow(), e.currentTarget.offsetLeft, e.currentTarget.offsetTop + e.currentTarget.clientHeight + 10);
|
||||
},
|
||||
handleLoginClick: function () {
|
||||
this.transitionTo('login');
|
||||
},
|
||||
handleLogoutClick: function () {
|
||||
accountActions.logout();
|
||||
},
|
||||
render: function () {
|
||||
let updateWidget = this.state.updateAvailable ? <a className="btn btn-action small no-drag" onClick={this.handleAutoUpdateClick}>UPDATE NOW</a> : null;
|
||||
let buttons;
|
||||
@@ -91,7 +106,11 @@ var Header = React.createClass({
|
||||
if (this.props.hideLogin) {
|
||||
username = null;
|
||||
} else if (this.state.username) {
|
||||
username = <span>{this.state.username}</span>;
|
||||
username = (
|
||||
<span className="no-drag" onClick={this.handleUserClick}>
|
||||
<RetinaImage src="user.png"/> {this.state.username} <RetinaImage src="userdropdown.png"/>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
username = (
|
||||
<span className="no-drag" onClick={this.handleLoginClick}>
|
||||
@@ -100,8 +119,14 @@ var Header = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
let headerClasses = classNames({
|
||||
bordered: !this.props.hideLogin,
|
||||
header: true,
|
||||
'no-drag': true
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="header no-drag">
|
||||
<div className={headerClasses}>
|
||||
{buttons}
|
||||
<div className="updates">
|
||||
{updateWidget}
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var React = require('react');
|
||||
var RetinaImage = require('react-retina-image');
|
||||
var Radial = require('./Radial.react');
|
||||
var ImageCard = require('./ImageCard.react');
|
||||
var Promise = require('bluebird');
|
||||
var metrics = require('../utils/MetricsUtil');
|
||||
var classNames = require('classnames');
|
||||
|
||||
var _recommended = [];
|
||||
var _searchPromise = null;
|
||||
|
||||
var NewContainer = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
query: '',
|
||||
loading: false,
|
||||
results: _recommended
|
||||
};
|
||||
},
|
||||
componentDidMount: function () {
|
||||
this.refs.searchInput.getDOMNode().focus();
|
||||
this.recommended();
|
||||
},
|
||||
componentWillUnmount: function () {
|
||||
if (_searchPromise) {
|
||||
_searchPromise.cancel();
|
||||
}
|
||||
},
|
||||
search: function (query) {
|
||||
if (_searchPromise) {
|
||||
_searchPromise.cancel();
|
||||
_searchPromise = null;
|
||||
}
|
||||
|
||||
if (!query.length) {
|
||||
this.setState({
|
||||
query: query,
|
||||
results: _recommended,
|
||||
loading: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
query: query,
|
||||
loading: true
|
||||
});
|
||||
|
||||
_searchPromise = Promise.delay(200).then(() => Promise.resolve($.get('https://registry.hub.docker.com/v1/search?q=' + query))).cancellable().then(data => {
|
||||
metrics.track('Searched for Images');
|
||||
this.setState({
|
||||
results: data.results,
|
||||
query: query,
|
||||
loading: false
|
||||
});
|
||||
_searchPromise = null;
|
||||
}).catch(Promise.CancellationError, () => {
|
||||
});
|
||||
},
|
||||
recommended: function () {
|
||||
if (_recommended.length) {
|
||||
return;
|
||||
}
|
||||
Promise.resolve($.ajax({
|
||||
url: 'https://kitematic.com/recommended.json',
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
})).then(res => res.repos).map(repo => {
|
||||
var query = repo.repo;
|
||||
var vals = query.split('/');
|
||||
if (vals.length === 1) {
|
||||
query = 'library/' + vals[0];
|
||||
}
|
||||
return $.get('https://registry.hub.docker.com/v1/repositories_info/' + query).then(data => {
|
||||
var res = _.extend(data, repo);
|
||||
res.description = data.short_description;
|
||||
res.is_official = data.namespace === 'library';
|
||||
res.name = data.repo;
|
||||
res.star_count = data.stars;
|
||||
return res;
|
||||
});
|
||||
}).then(results => {
|
||||
_recommended = results.filter(r => !!r);
|
||||
if (!this.state.query.length && this.isMounted()) {
|
||||
this.setState({
|
||||
results: _recommended
|
||||
});
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
handleChange: function (e) {
|
||||
var query = e.target.value;
|
||||
if (query === this.state.query) {
|
||||
return;
|
||||
}
|
||||
this.search(query);
|
||||
},
|
||||
render: function () {
|
||||
var title = this.state.query ? 'Results' : 'Recommended';
|
||||
var data = this.state.results;
|
||||
var results;
|
||||
if (data.length) {
|
||||
var items = data.map(function (image) {
|
||||
return (
|
||||
<ImageCard key={image.name} image={image} />
|
||||
);
|
||||
});
|
||||
|
||||
results = (
|
||||
<div className="result-grid">
|
||||
{items}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
if (this.state.results.length === 0 && this.state.query === '') {
|
||||
results = (
|
||||
<div className="no-results">
|
||||
<div className="loader">
|
||||
<h2>Loading Images</h2>
|
||||
<Radial spin="true" progress={90} thick={true} transparent={true} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
results = (
|
||||
<div className="no-results">
|
||||
<h1>Cannot find a matching image.</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
var loadingClasses = classNames({
|
||||
hidden: !this.state.loading,
|
||||
loading: true
|
||||
});
|
||||
var magnifierClasses = classNames({
|
||||
hidden: this.state.loading,
|
||||
icon: true,
|
||||
'icon-magnifier': true,
|
||||
'search-icon': true
|
||||
});
|
||||
return (
|
||||
<div className="details">
|
||||
<div className="new-container">
|
||||
<div className="new-container-header">
|
||||
<div className="text">
|
||||
Select a Docker image to create a new container.
|
||||
</div>
|
||||
<div className="search">
|
||||
<div className="search-bar">
|
||||
<input type="search" ref="searchInput" className="form-control" placeholder="Search Docker Hub for an image" onChange={this.handleChange}/>
|
||||
<div className={magnifierClasses}></div>
|
||||
<RetinaImage className={loadingClasses} src="loading.png"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="results">
|
||||
<h4>{title}</h4>
|
||||
{results}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = NewContainer;
|
||||
@@ -1,7 +1,4 @@
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var React = require('react/addons');
|
||||
var RetinaImage = require('react-retina-image');
|
||||
var ImageCard = require('./ImageCard.react');
|
||||
var Promise = require('bluebird');
|
||||
var metrics = require('../utils/MetricsUtil');
|
||||
@@ -15,12 +12,19 @@ module.exports = React.createClass({
|
||||
return {
|
||||
query: '',
|
||||
loading: false,
|
||||
results: _recommended
|
||||
category: 'recommended',
|
||||
recommendedrepos: [],
|
||||
publicrepos: [],
|
||||
userrepos: [],
|
||||
results: [],
|
||||
tab: 'all'
|
||||
};
|
||||
},
|
||||
componentDidMount: function () {
|
||||
// fetch recommended
|
||||
// fetch public repos
|
||||
// if logged in: my repos
|
||||
this.refs.searchInput.getDOMNode().focus();
|
||||
this.recommended();
|
||||
},
|
||||
componentWillUnmount: function () {
|
||||
if (_searchPromise) {
|
||||
@@ -47,49 +51,11 @@ module.exports = React.createClass({
|
||||
loading: true
|
||||
});
|
||||
|
||||
_searchPromise = Promise.delay(200).cancellable().then(() => Promise.resolve($.get('https://registry.hub.docker.com/v1/search?q=' + query))).then(data => {
|
||||
_searchPromise = Promise.delay(200).cancellable().then(() => {
|
||||
metrics.track('Searched for Images');
|
||||
this.setState({
|
||||
results: data.results,
|
||||
query: query,
|
||||
loading: false
|
||||
});
|
||||
_searchPromise = null;
|
||||
}).catch(Promise.CancellationError, () => {
|
||||
});
|
||||
},
|
||||
recommended: function () {
|
||||
if (_recommended.length) {
|
||||
return;
|
||||
}
|
||||
Promise.resolve($.ajax({
|
||||
url: 'https://kitematic.com/recommended.json',
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
})).then(res => res.repos).map(repo => {
|
||||
var query = repo.repo;
|
||||
var vals = query.split('/');
|
||||
if (vals.length === 1) {
|
||||
query = 'library/' + vals[0];
|
||||
}
|
||||
return $.get('https://registry.hub.docker.com/v1/repositories_info/' + query).then(data => {
|
||||
var res = _.extend(data, repo);
|
||||
res.description = data.short_description;
|
||||
res.is_official = data.namespace === 'library';
|
||||
res.name = data.repo;
|
||||
res.star_count = data.stars;
|
||||
return res;
|
||||
});
|
||||
}).then(results => {
|
||||
_recommended = results.filter(r => !!r);
|
||||
if (!this.state.query.length && this.isMounted()) {
|
||||
this.setState({
|
||||
results: _recommended
|
||||
});
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
// TODO: call search action
|
||||
}).catch(Promise.CancellationError, () => {});
|
||||
},
|
||||
handleChange: function (e) {
|
||||
var query = e.target.value;
|
||||
@@ -99,8 +65,7 @@ module.exports = React.createClass({
|
||||
this.search(query);
|
||||
},
|
||||
render: function () {
|
||||
var title = this.state.query ? 'Results' : 'Recommended';
|
||||
var data = this.state.results;
|
||||
var data = this.state.recommendedrepos;
|
||||
var results;
|
||||
if (data.length) {
|
||||
var items = data.map(function (image) {
|
||||
@@ -132,7 +97,8 @@ module.exports = React.createClass({
|
||||
);
|
||||
}
|
||||
}
|
||||
var loadingClasses = classNames({
|
||||
|
||||
let loadingClasses = classNames({
|
||||
hidden: !this.state.loading,
|
||||
spinner: true,
|
||||
loading: true,
|
||||
@@ -140,12 +106,18 @@ module.exports = React.createClass({
|
||||
'la-dark': true,
|
||||
'la-sm': true
|
||||
});
|
||||
var magnifierClasses = classNames({
|
||||
|
||||
let magnifierClasses = classNames({
|
||||
hidden: this.state.loading,
|
||||
icon: true,
|
||||
'icon-magnifier': true,
|
||||
'search-icon': true
|
||||
});
|
||||
|
||||
let allTabClasses = classNames({
|
||||
'results-filter':
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="details">
|
||||
<div className="new-container">
|
||||
@@ -162,7 +134,12 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
</div>
|
||||
<div className="results">
|
||||
<h4>{title}</h4>
|
||||
<div className="results-filters">
|
||||
<span className="results-filter results-filter-title">FILTER BY</span>
|
||||
<span className="results-filter results-all tab">All</span>
|
||||
<span className="results-filter results-recommended tab">Recommended</span>
|
||||
<span className="results-filter results-userrepos tab">My Repositories</span>
|
||||
</div>
|
||||
{results}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,6 @@ var Router = require('react-router');
|
||||
var Route = Router.Route;
|
||||
var DefaultRoute = Router.DefaultRoute;
|
||||
var RouteHandler = Router.RouteHandler;
|
||||
var Redirect = Router.Redirect;
|
||||
|
||||
var App = React.createClass({
|
||||
render: function () {
|
||||
@@ -52,7 +51,6 @@ var routes = (
|
||||
<Route name="preferences" path="/preferences" handler={Preferences}/>
|
||||
</Route>
|
||||
<DefaultRoute name="setup" handler={Setup}/>
|
||||
<Redirect from="containers/details/:name" to="containerHome"/>
|
||||
</Route>
|
||||
);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ class AccountStore {
|
||||
this.bindActions(accountServerActions);
|
||||
this.bindActions(accountActions);
|
||||
|
||||
this.prompted = localStorage.getItem('account.prompted') || false;
|
||||
this.prompted = false;
|
||||
this.loading = false;
|
||||
this.errors = {};
|
||||
|
||||
@@ -19,7 +19,6 @@ class AccountStore {
|
||||
this.setState({
|
||||
prompted: true
|
||||
});
|
||||
localStorage.setItem('account.prompted', true);
|
||||
}
|
||||
|
||||
login () {
|
||||
@@ -29,6 +28,15 @@ class AccountStore {
|
||||
});
|
||||
}
|
||||
|
||||
logout () {
|
||||
this.setState({
|
||||
loading: false,
|
||||
errors: {},
|
||||
username: null,
|
||||
verified: false
|
||||
});
|
||||
}
|
||||
|
||||
signup () {
|
||||
this.setState({
|
||||
loading: true,
|
||||
@@ -48,6 +56,10 @@ class AccountStore {
|
||||
this.setState({verified});
|
||||
}
|
||||
|
||||
prompted ({prompted}) {
|
||||
this.setState({prompted});
|
||||
}
|
||||
|
||||
errors ({errors}) {
|
||||
this.setState({errors, loading: false});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ class RepositoryStore {
|
||||
constructor () {
|
||||
this.bindActions(repositoryServerActions);
|
||||
this.repos = [];
|
||||
this.recommended = [];
|
||||
this.userrepos = [];
|
||||
this.loading = false;
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,16 @@ var request = require('request');
|
||||
var accountServerActions = require('../actions/AccountServerActions');
|
||||
|
||||
module.exports = {
|
||||
|
||||
init: function () {
|
||||
accountServerActions.prompted({prompted: localStorage.getItem('auth.prompted')});
|
||||
if (this.jwt()) { // TODO: check for config too
|
||||
let username = localStorage.getItem('auth.username');
|
||||
let verified = localStorage.getItem('auth.verified');
|
||||
accountServerActions.loggedin({username, verified});
|
||||
}
|
||||
},
|
||||
|
||||
// Returns the base64 encoded index token or null if no token exists
|
||||
config: function () {
|
||||
let config = localStorage.getItem('auth.config');
|
||||
@@ -11,6 +21,11 @@ module.exports = {
|
||||
return config;
|
||||
},
|
||||
|
||||
prompted: function (prompted) {
|
||||
localStorage.setItem('auth.prompted', true);
|
||||
accountServerActions.prompted({prompted});
|
||||
},
|
||||
|
||||
// Retrives the current jwt hub token or null if no token exists
|
||||
jwt: function () {
|
||||
let jwt = localStorage.getItem('auth.jwt');
|
||||
@@ -20,8 +35,16 @@ module.exports = {
|
||||
return jwt;
|
||||
},
|
||||
|
||||
loggedin: function () {
|
||||
return this.jwt() && this.config();
|
||||
refresh: function () {
|
||||
// TODO: implement me
|
||||
},
|
||||
|
||||
logout: function () {
|
||||
localStorage.removeItem('auth.jwt');
|
||||
localStorage.removeItem('auth.username');
|
||||
localStorage.removeItem('auth.verified');
|
||||
localStorage.removeItem('auth.config');
|
||||
accountServerActions.loggedout();
|
||||
},
|
||||
|
||||
// Places a token under ~/.dockercfg and saves a jwt to localstore
|
||||
@@ -30,8 +53,10 @@ module.exports = {
|
||||
let data = JSON.parse(body);
|
||||
if (response.statusCode === 200) {
|
||||
// TODO: save username to localstorage
|
||||
// TODO: handle case where token does not exist
|
||||
if (data.token) {
|
||||
localStorage.setItem('auth.jwt', data.token);
|
||||
localStorage.setItem('auth.username', username);
|
||||
}
|
||||
accountServerActions.loggedin({username, verified: true});
|
||||
} else if (response.statusCode === 401) {
|
||||
@@ -56,7 +81,7 @@ module.exports = {
|
||||
}, (err, response, body) => {
|
||||
// TODO: save username to localstorage
|
||||
if (response.statusCode === 204) {
|
||||
accountServerActions.signedup({username});
|
||||
accountServerActions.signedup({username, verified: false});
|
||||
} else {
|
||||
let data = JSON.parse(body);
|
||||
let errors = {};
|
||||
|
||||
@@ -3,6 +3,40 @@ var async = require('async');
|
||||
var repositoryServerActions = require('../actions/RepositoryServerActions');
|
||||
|
||||
module.exports = {
|
||||
search: function (query) {
|
||||
if (!query) {
|
||||
return;
|
||||
}
|
||||
|
||||
request.get({
|
||||
url: 'https://registry.hub.docker.com/v1/search?',
|
||||
qs: {q: query}
|
||||
}, (error, response, body) => {
|
||||
if (error) {
|
||||
// TODO: report search error
|
||||
}
|
||||
|
||||
let data = JSON.parse(body);
|
||||
if (response.statusCode === 200) {
|
||||
repositoryServerActions.searched({});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
recommended: function () {
|
||||
request.get('https://kitematic.com/recommended.json', (error, response, body) => {
|
||||
if (error) {
|
||||
// TODO: report search error
|
||||
}
|
||||
|
||||
let data = JSON.parse(body);
|
||||
console.log(data);
|
||||
if (response.statusCode === 200) {
|
||||
repositoryServerActions.recommended({});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Returns the base64 encoded index token or null if no token exists
|
||||
repos: function (jwt) {
|
||||
|
||||
@@ -28,6 +62,7 @@ module.exports = {
|
||||
}, (error, response, body) => {
|
||||
if (error) {
|
||||
repositoryServerActions.error({error});
|
||||
return;
|
||||
}
|
||||
|
||||
let data = JSON.parse(body);
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
|
||||
border-bottom: 1px solid #E7E7E7;
|
||||
&.bordered {
|
||||
border-bottom: 1px solid #E7E7E7;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
|
||||
@@ -30,7 +32,7 @@
|
||||
color: #88919C;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-right: 30px;
|
||||
margin-right: 13px;
|
||||
|
||||
&:active {
|
||||
img, span {
|
||||
|
||||
@@ -36,6 +36,27 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 auto;
|
||||
color: @gray-normal;
|
||||
|
||||
.results-filters {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
font-size: 13px;
|
||||
|
||||
.results-filter {
|
||||
text-align: center;
|
||||
margin: 0 10px;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.results-filter-title {
|
||||
color: @gray-lighter;
|
||||
font-weight: 500;
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-results {
|
||||
flex: 1 auto;
|
||||
display: flex;
|
||||
@@ -64,18 +85,17 @@
|
||||
}
|
||||
}
|
||||
.new-container-header {
|
||||
margin-bottom: 18px;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
flex: 0 auto;
|
||||
.text {
|
||||
flex: 1 auto;
|
||||
width: 50%;
|
||||
font-size: 14px;
|
||||
color: @gray-lighter;
|
||||
color: @gray-normal;
|
||||
}
|
||||
.search {
|
||||
flex: 1 auto;
|
||||
margin-right: 30px;
|
||||
.search-bar {
|
||||
top: -7px;
|
||||
position: relative;
|
||||
@@ -105,7 +125,7 @@
|
||||
border-color: @brand-primary;
|
||||
}
|
||||
&::-webkit-input-placeholder {
|
||||
color: @gray-lightest;
|
||||
color: @gray-lighter;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,28 +65,6 @@
|
||||
text-align: right;
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
.tab {
|
||||
margin-left: 16px;
|
||||
padding: 6px 10px;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
&:hover {
|
||||
border-radius: 40px;
|
||||
background-color: darken(@color-background, 2%);
|
||||
}
|
||||
&.active {
|
||||
border-radius: 40px;
|
||||
color: white;
|
||||
.brand-gradient();
|
||||
}
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
&:hover {
|
||||
border-radius: 40px;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.details-header {
|
||||
@@ -123,6 +101,26 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
margin-left: 16px;
|
||||
padding: 6px 10px;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
&.active {
|
||||
border-radius: 40px;
|
||||
color: white;
|
||||
.brand-gradient();
|
||||
}
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
&:hover {
|
||||
border-radius: 40px;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details-progress {
|
||||
margin: 20% auto 0;
|
||||
text-align: center;
|
||||
|
||||
@@ -164,6 +164,14 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
-webkit-app-region: no-drag;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
flex: 1 auto;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user