aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json2
-rw-r--r--src/web/js/actions/MenuActions.js2
-rw-r--r--src/web/js/components/MainApp.react.js26
-rw-r--r--src/web/js/components/Menu.react.js10
-rw-r--r--src/web/js/components/MiddlePanel.react.js8
-rw-r--r--src/web/js/components/Navbar.react.js91
-rw-r--r--src/web/js/components/RightPanel.react.js13
-rw-r--r--src/web/js/stores/MenuStore.js3
-rw-r--r--src/web/static/css/customized-bootstrap.css11
-rw-r--r--src/web/templates/home2.html82
-rw-r--r--src/web/views/feed.py5
-rw-r--r--src/web/views/views.py2
12 files changed, 146 insertions, 109 deletions
diff --git a/package.json b/package.json
index 01ab12f8..2ad26f07 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"keymirror": "~0.1.0",
"object-assign": "^1.0.0",
"react": "^0.14.6",
- "react-bootstrap": "^0.14.1",
+ "react-bootstrap": "^0.28.0",
"react-dom": "^0.14.6",
"react-intl": "^1.2.2"
},
diff --git a/src/web/js/actions/MenuActions.js b/src/web/js/actions/MenuActions.js
index 4b17d084..fa30474e 100644
--- a/src/web/js/actions/MenuActions.js
+++ b/src/web/js/actions/MenuActions.js
@@ -11,6 +11,8 @@ var MenuActions = {
type: ActionTypes.RELOAD_MENU,
feeds: payload.feeds,
categories: payload.categories,
+ is_admin: payload.is_admin,
+ crawling_method: payload.crawling_method,
all_unread_count: payload.all_unread_count,
});
});
diff --git a/src/web/js/components/MainApp.react.js b/src/web/js/components/MainApp.react.js
index b448f808..cbdc5833 100644
--- a/src/web/js/components/MainApp.react.js
+++ b/src/web/js/components/MainApp.react.js
@@ -1,7 +1,8 @@
var React = require('react');
-var Col = require('react-bootstrap/Col');
-var Grid = require('react-bootstrap/Grid');
+var Col = require('react-bootstrap/lib/Col');
+var Grid = require('react-bootstrap/lib/Grid');
+var JarrNavBar = require('./Navbar.react');
var Menu = require('./Menu.react');
var MiddlePanel = require('./MiddlePanel.react');
var RightPanel = require('./RightPanel.react');
@@ -9,15 +10,18 @@ var RightPanel = require('./RightPanel.react');
var MainApp = React.createClass({
render: function() {
- return (<Grid fluid id="jarr-container">
- <Menu />
- <Col id="middle-panel" mdOffset={3} lgOffset={2}
- xs={2} sm={2} md={4} lg={4}>
- <MiddlePanel.MiddlePanelFilter />
- <MiddlePanel.MiddlePanel />
- </Col>
- <RightPanel />
- </Grid>
+ return (<div>
+ <JarrNavBar />
+ <Grid fluid id="jarr-container">
+ <Menu />
+ <Col id="middle-panel" mdOffset={3} lgOffset={2}
+ xs={4} sm={4} md={4} lg={4}>
+ <MiddlePanel.MiddlePanelFilter />
+ <MiddlePanel.MiddlePanel />
+ </Col>
+ <RightPanel />
+ </Grid>
+ </div>
);
},
});
diff --git a/src/web/js/components/Menu.react.js b/src/web/js/components/Menu.react.js
index 0d739e4e..ad28015c 100644
--- a/src/web/js/components/Menu.react.js
+++ b/src/web/js/components/Menu.react.js
@@ -1,9 +1,9 @@
var React = require('react');
-var Col = require('react-bootstrap/Col');
-var Badge = require('react-bootstrap/Badge');
-var Button = require('react-bootstrap/Button');
-var ButtonGroup = require('react-bootstrap/ButtonGroup');
-var Glyphicon = require('react-bootstrap/Glyphicon');
+var Col = require('react-bootstrap/lib/Col');
+var Badge = require('react-bootstrap/lib/Badge');
+var Button = require('react-bootstrap/lib/Button');
+var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
+var Glyphicon = require('react-bootstrap/lib/Glyphicon');
var MenuStore = require('../stores/MenuStore');
var MenuActions = require('../actions/MenuActions');
diff --git a/src/web/js/components/MiddlePanel.react.js b/src/web/js/components/MiddlePanel.react.js
index 6bfdaaa9..fd291624 100644
--- a/src/web/js/components/MiddlePanel.react.js
+++ b/src/web/js/components/MiddlePanel.react.js
@@ -1,9 +1,9 @@
var React = require('react');
-var Row = require('react-bootstrap/Row');
-var Button = require('react-bootstrap/Button');
-var ButtonGroup = require('react-bootstrap/ButtonGroup');
-var Glyphicon = require('react-bootstrap/Glyphicon');
+var Row = require('react-bootstrap/lib/Row');
+var Button = require('react-bootstrap/lib/Button');
+var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
+var Glyphicon = require('react-bootstrap/lib/Glyphicon');
var MiddlePanelStore = require('../stores/MiddlePanelStore');
var MiddlePanelActions = require('../actions/MiddlePanelActions');
diff --git a/src/web/js/components/Navbar.react.js b/src/web/js/components/Navbar.react.js
new file mode 100644
index 00000000..56de178e
--- /dev/null
+++ b/src/web/js/components/Navbar.react.js
@@ -0,0 +1,91 @@
+var React = require('react');
+var Glyphicon = require('react-bootstrap/lib/Glyphicon');
+var Nav = require('react-bootstrap/lib/Nav');
+var NavItem = require('react-bootstrap/lib/NavItem');
+var Navbar = require('react-bootstrap/lib/Navbar');
+var NavDropdown = require('react-bootstrap/lib/NavDropdown');
+var MenuItem = require('react-bootstrap/lib/MenuItem');
+var Button = require('react-bootstrap/lib/Button');
+var Input = require('react-bootstrap/lib/Input');
+
+var MenuStore = require('../stores/MenuStore');
+
+JarrNavBar = React.createClass({
+ getInitialState: function() {
+ return {is_admin: MenuStore._datas.is_admin,
+ crawling_method: MenuStore._datas.crawling_method};
+ },
+ buttonFetch: function() {
+ if(this.state.is_admin && this.state.crawling_method != 'http') {
+ return <NavItem eventKey={2} href="/fetch"><Glyphicon glyph="import" />Fetch</NavItem>;
+ }
+ },
+ buttonAdmin: function() {
+ if(this.state.is_admin) {
+ return (<NavDropdown title={<Glyphicon glyph='cog' />}
+ id='admin-dropdown'>
+ <MenuItem href="/admin/dashboard">
+ <Glyphicon glyph="dashboard" />Dashboard
+ </MenuItem>
+ </NavDropdown>);
+ }
+ },
+ render: function() {
+ var gl_title = (<span>
+ <Glyphicon glyph="plus-sign" />Add a new feed
+ </span>);
+ return (<Navbar fixedTop inverse className="navbar-custom">
+ <Navbar.Header>
+ <Navbar.Brand>
+ <a href="/">JARR</a>
+ </Navbar.Brand>
+ <Navbar.Toggle />
+ </Navbar.Header>
+ <Nav pullRight>
+ <Navbar.Form pullLeft>
+ <form action="/feed/bookmarklet" method="GET">
+ <Input name="url" type="text"
+ placeholder="Add a new feed" />
+ <Button type="submit">Submit</Button>
+ </form>
+ </Navbar.Form>
+ {this.buttonFetch()}
+ <NavDropdown title="Feed" id="feed-mgmt-dropdown">
+ <MenuItem href="/feeds/inactives">Inactive</MenuItem>
+ <MenuItem href="/articles/history">History</MenuItem>
+ <MenuItem href="/feeds/">All</MenuItem>
+ </NavDropdown>
+ {this.buttonAdmin()}
+ <NavDropdown title={<Glyphicon glyph='user' />}
+ id="user-dropdown">
+ <MenuItem href="/user/profile">
+ <Glyphicon glyph="user" />Profile
+ </MenuItem>
+ <MenuItem href="/user/management">
+ <Glyphicon glyph="cog" />Your data
+ </MenuItem>
+ <MenuItem href="/about">
+ <Glyphicon glyph="question-sign" />About
+ </MenuItem>
+ <MenuItem href="/logout">
+ <Glyphicon glyph="log-out" />Logout
+ </MenuItem>
+ </NavDropdown>
+ </Nav>
+ </Navbar>
+ );
+ },
+ componentDidMount: function() {
+ MenuStore.addChangeListener(this._onChange);
+ },
+ componentWillUnmount: function() {
+ MenuStore.removeChangeListener(this._onChange);
+ },
+ _onChange: function() {
+ var datas = MenuStore.getAll();
+ this.setState({is_admin: datas.is_admin,
+ crawling_method: datas.crawling_method});
+ },
+});
+
+module.exports = JarrNavBar;
diff --git a/src/web/js/components/RightPanel.react.js b/src/web/js/components/RightPanel.react.js
index fda7c976..e9485511 100644
--- a/src/web/js/components/RightPanel.react.js
+++ b/src/web/js/components/RightPanel.react.js
@@ -1,8 +1,8 @@
var React = require('react');
-var Col = require('react-bootstrap/Col');
-var Glyphicon = require('react-bootstrap/Glyphicon');
-var Button = require('react-bootstrap/Button');
-var ButtonGroup = require('react-bootstrap/ButtonGroup');
+var Col = require('react-bootstrap/lib/Col');
+var Glyphicon = require('react-bootstrap/lib/Glyphicon');
+var Button = require('react-bootstrap/lib/Button');
+var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
var RightPanelActions = require('../actions/RightPanelActions');
var RightPanelStore = require('../stores/RightPanelStore');
@@ -293,7 +293,6 @@ var RightPanel = React.createClass({
return <li>{this.state.article.title}</li>;
},
render: function() {
- var content = null;
var brd_category = null;
var brd_feed = null;
var brd_article = null;
@@ -329,9 +328,9 @@ var RightPanel = React.createClass({
key={this.state.category.id} />);
}
- return (<Col id="right-panel" xsOffset={2} smOffset={2}
+ return (<Col id="right-panel" xsOffset={4} smOffset={4}
mdOffset={7} lgOffset={6}
- xs={10} sm={10} md={5} lg={6}>
+ xs={8} sm={8} md={5} lg={6}>
{breadcrum}
{cntnt}
</Col>
diff --git a/src/web/js/stores/MenuStore.js b/src/web/js/stores/MenuStore.js
index edc90a38..b8f50fd9 100644
--- a/src/web/js/stores/MenuStore.js
+++ b/src/web/js/stores/MenuStore.js
@@ -8,6 +8,7 @@ var assign = require('object-assign');
var MenuStore = assign({}, EventEmitter.prototype, {
_datas: {filter: 'all', feeds: {}, categories: {},
active_type: null, active_id: null,
+ is_admin: false, crawling_method: 'classic',
all_unread_count: 0},
getAll: function() {
return this._datas;
@@ -45,6 +46,8 @@ MenuStore.dispatchToken = JarrDispatcher.register(function(action) {
case ActionTypes.RELOAD_MENU:
MenuStore._datas['feeds'] = action.feeds;
MenuStore._datas['categories'] = action.categories;
+ MenuStore._datas['is_admin'] = action.is_admin;
+ MenuStore._datas['crawling_method'] = action.crawling_method;
MenuStore._datas['all_unread_count'] = action.all_unread_count;
MenuStore.emitChange();
break;
diff --git a/src/web/static/css/customized-bootstrap.css b/src/web/static/css/customized-bootstrap.css
index 9f3febfc..db789f56 100644
--- a/src/web/static/css/customized-bootstrap.css
+++ b/src/web/static/css/customized-bootstrap.css
@@ -8,11 +8,20 @@ div.top {
height: 0;
}
-.navbar-custom {
+nav.navbar-custom {
background-color: #205081;
border: #205081;
border-radius: 0;
}
+nav.navbar-custom>div.container {
+ width: 100%;
+}
+nav.navbar-custom span.glyphicon {
+ margin-right: 5px;
+}
+nav.navbar-custom button {
+ margin-left: 5px;
+}
.navbar-custom .navbar-nav > li > a {
color: #FFFFFF;
diff --git a/src/web/templates/home2.html b/src/web/templates/home2.html
index 36dd8f19..4389ae6f 100644
--- a/src/web/templates/home2.html
+++ b/src/web/templates/home2.html
@@ -16,85 +16,7 @@
{% endblock %}
</head>
<body>
- <nav class="navbar navbar-inverse navbar-fixed-top navbar-custom" role="navigation">
- <div class="container-fluid">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
- <span class="sr-only">Toggle navigation</span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="{{ url_for("home") }}">JARR</a>
- {% if head_titles %}
- <p class="navbar-text" style="max-height: 20px; overflow: hidden">
- {{ " - ".join(head_titles) }}
- </p>
- {% endif %}
- </div>
-
- <!-- Collect the nav links, forms, and other content for toggling -->
- <div class="collapse navbar-collapse navbar-ex1-collapse">
- <ul class="nav navbar-nav navbar-right">
- {% if g.user.is_authenticated %}
- <!-- <li><a href="{{ url_for("feed.form") }}"><span class="glyphicon glyphicon-plus-sign"></span> {{ _('Add a feed') }}</a></li> -->
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown">
- <div><span class="glyphicon glyphicon-plus-sign"></span>&nbsp;{{ _('Add a feed') }}</div>
- </a>
- <ul class="dropdown-menu">
- <li>
- <form action="{{ url_for('feed.bookmarklet') }}" class="navbar-form navbar-left" method="GET" name="save">
- <div class="input-group input-group-inline">
- <input class="form-control" name="url" type="url" placeholder="{{_("site or feed url")}}" required="required"/>
- <span class="input-group-btn">
- <button type="submit" class="btn btn-default" /><span class="glyphicon glyphicon-plus"></span></button>
- </span>
- </div><!-- /input-group -->
- </form>
- </li>
- </ul>
- </li>
- {% if conf.CRAWLING_METHOD == "classic" and (not conf.ON_HEROKU or g.user.is_admin()) %}
- <li><a href="/fetch"><span class="glyphicon glyphicon-import"></span> {{ _('Fetch') }}</a></li>
- {% endif %}
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ _('Feed') }} <b class="caret"></b></a>
- <ul class="dropdown-menu">
- <li><a href="{{ url_for("feeds.update", action="read") }}">{{ _('Mark all as read') }}</a></li>
- <li><a href="{{ url_for("feeds.update", action="read", nb_days="1") }}">{{ _('Mark all as read older than yesterday') }}</a></li>
- <li><a href="{{ url_for("feeds.update", action="read", nb_days="5") }}">{{ gettext('Mark all as read older than %(days)s days', days=5) }}</a></li>
- <li><a href="{{ url_for("feeds.update", action="read", nb_days="10") }}">{{ gettext('Mark all as read older than %(days)s days', days=10) }}</a></li>
- <li role="presentation" class="divider"></li>
- <li><a href="{{ url_for("feeds.inactives") }}">{{ _('Inactive') }}</a></li>
- <li><a href="{{ url_for("articles.history") }}">{{ _('History') }}</a></li>
- <li><a href="{{ url_for("feeds.feeds") }}">{{ _('All') }}</a></li>
- </ul>
- </li>
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown">
- <div><span class="glyphicon glyphicon-user"></span>&nbsp;<b class="caret"></b></div>
- </a>
- <ul class="dropdown-menu">
- <li><a href="{{ url_for("user.profile") }}"><span class="glyphicon glyphicon-user"></span> {{ _('Profile') }}</a></li>
- <li><a href="{{ url_for("user.management") }}"><span class="glyphicon glyphicon-cog"></span> {{ _('Your data') }}</a></li>
- <li><a href="{{ url_for("about") }}"><span class="glyphicon glyphicon-question-sign"></span> {{ _('About') }}</a></li>
- {% if g.user.is_admin() %}
- <li role="presentation" class="divider"></li>
- <li><a href="{{ url_for("admin.dashboard") }}"><span class="glyphicon glyphicon-dashboard"></span> {{ _('Dashboard') }}</a></li>
- <li role="presentation" class="divider"></li>
- {% endif %}
- <li><a href="{{ url_for("logout") }}"><span class="glyphicon glyphicon-log-out"></span> {{ _('Logout') }}</a></li>
- </ul>
- </li>
- {% else %}
- <li><a href="{{ url_for("about") }}"><span class="glyphicon glyphicon-question-sign"></span>&nbsp;{{ _('About') }}</a></li>
- {% endif %}
- </ul>
- </div><!-- /.navbar-collapse -->
- </div><!-- /.container -->
- </nav>
- <section id="jarrapp"></section>
- <script type="text/javascript" src="{{ url_for('static', filename = 'js/bundle.min.js') }}"></script>
+ <section id="jarrapp" />
</body>
+ <script type="text/javascript" src="{{ url_for('static', filename = 'js/bundle.min.js') }}"></script>
</html>
diff --git a/src/web/views/feed.py b/src/web/views/feed.py
index 69972958..9de45a7e 100644
--- a/src/web/views/feed.py
+++ b/src/web/views/feed.py
@@ -1,5 +1,6 @@
#! /usr/bin/env python
# -*- coding: utf-8 -
+import logging
import requests.exceptions
from datetime import datetime, timedelta
from sqlalchemy import desc
@@ -18,6 +19,7 @@ from web.forms import AddFeedForm
from web.controllers import (CategoryController, FeedController,
ArticleController)
+logger = logging.getLogger(__name__)
feeds_bp = Blueprint('feeds', __name__, url_prefix='/feeds')
feed_bp = Blueprint('feed', __name__, url_prefix='/feed')
@@ -114,6 +116,9 @@ def bookmarklet():
flash(gettext("Impossible to connect to the address: {}.".format(url)),
"danger")
return redirect(url_for('home'))
+ except Exception:
+ logger.exception('something bad happened when fetching %r', url)
+ return redirect(url_for('home'))
if not feed.get('link'):
feed['enabled'] = False
flash(gettext("Couldn't find a feed url, you'll need to find a Atom or"
diff --git a/src/web/views/views.py b/src/web/views/views.py
index f8549e93..1aed912d 100644
--- a/src/web/views/views.py
+++ b/src/web/views/views.py
@@ -262,6 +262,8 @@ def get_menu():
categories[feed['category_id']]['unread'] += feed['unread']
categories[feed['category_id']]['feeds'].append(feed_id)
return jsonify(**{'feeds': feeds, 'categories': categories,
+ 'crawling_method': conf.CRAWLING_METHOD,
+ 'is_admin': g.user.is_admin(),
'all_unread_count': sum(unread.values())})
bgstack15