Add offline mode for Semantic UI.

Following a similar guide to:
https://github.com/Semantic-Org/Semantic-UI/issues/1521

Using a new endpoint to handle offline mode to host semantic.min.css and
other CSS files.  Need to wrap these in templates to provide URL for
static font files when hosting under a directory.
This commit is contained in:
Mike Terzo
2017-07-07 17:01:33 -04:00
parent 548599bc59
commit e5c9b300ef
11 changed files with 78 additions and 2 deletions

View File

@@ -15,6 +15,7 @@ from flask import (
Response, stream_with_context, redirect, Response, stream_with_context, redirect,
request, session, jsonify request, session, jsonify
) )
from jinja2.utils import contextfunction
from pypuppetdb.QueryBuilder import * from pypuppetdb.QueryBuilder import *
@@ -1091,3 +1092,15 @@ def daily_reports_chart(env):
certname=certname, certname=certname,
) )
return jsonify(result=result) return jsonify(result=result)
@app.route('/offline/<path:filename>')
def offline_static(filename):
mimetype = 'text/html'
if filename.endswith('.css'):
mimetype = 'text/css'
elif filename.endswith('.js'):
mimetype = 'text/javascript'
return Response(response=render_template('static/%s' % filename),
status=200, mimetype=mimetype)

View File

@@ -7,7 +7,7 @@ from flask import Flask
from pypuppetdb import connect from pypuppetdb import connect
from puppetboard.utils import (jsonprint, prettyprint, url_for_field, from puppetboard.utils import (jsonprint, prettyprint, url_for_field,
get_or_abort) url_static_offline, get_or_abort)
from . import __version__ from . import __version__
@@ -31,6 +31,7 @@ def get_app():
app.jinja_env.filters['jsonprint'] = jsonprint app.jinja_env.filters['jsonprint'] = jsonprint
app.jinja_env.filters['prettyprint'] = prettyprint app.jinja_env.filters['prettyprint'] = prettyprint
app.jinja_env.globals['url_for_field'] = url_for_field app.jinja_env.globals['url_for_field'] = url_for_field
app.jinja_env.globals['url_static_offline'] = url_static_offline
APP = app APP = app
return APP return APP

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -13,11 +13,12 @@
} }
</style> </style>
<link href='{{ url_for('static', filename='jquery-datatables-1.10.13/dataTables.semanticui.min.css') }}' rel='stylesheet' type='text/css'> <link href='{{ url_for('static', filename='jquery-datatables-1.10.13/dataTables.semanticui.min.css') }}' rel='stylesheet' type='text/css'>
<link href="{{ url_for('offline_static', filename='Semantic-UI-2.1.8/semantic.min.css') }}" rel="stylesheet" />
{% else %} {% else %}
<link href='//fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css' /> <link href='//fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css' />
<link href="{{ url_for('static', filename='Semantic-UI-2.1.8/semantic.min.css') }}" rel="stylesheet" />
<link href='//cdnjs.cloudflare.com/ajax/libs/datatables/1.10.13/css/dataTables.semanticui.min.css' rel='stylesheet' type='text/css'> <link href='//cdnjs.cloudflare.com/ajax/libs/datatables/1.10.13/css/dataTables.semanticui.min.css' rel='stylesheet' type='text/css'>
{% endif %} {% endif %}
<link href="{{ url_for('static', filename='Semantic-UI-2.1.8/semantic.min.css') }}" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/puppetboard.css') }}" rel="stylesheet" /> <link href="{{ url_for('static', filename='css/puppetboard.css') }}" rel="stylesheet" />
{% if config.OFFLINE_MODE %} {% if config.OFFLINE_MODE %}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,24 @@
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url({{ url_for('static', filename='fonts/lato-normal-400.ttf') }}) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: local('Lato Bold'), local('Lato-Bold'), url({{ url_for('static', filename='fonts/lato-normal-700.ttf') }}) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: local('Lato Italic'), local('Lato-Italic'), url({{ url_for('static', filename='fonts/lato-italic-400.ttf') }}) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 700;
src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url({{ url_for('static', filename='fonts/lato-italic-700.ttf') }}) format('truetype');
}

View File

@@ -1,6 +1,7 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
import os.path
import json import json
import logging import logging
@@ -9,6 +10,7 @@ from requests.exceptions import HTTPError, ConnectionError
from pypuppetdb.errors import EmptyResponseError from pypuppetdb.errors import EmptyResponseError
from flask import abort, request, url_for from flask import abort, request, url_for
from jinja2.utils import contextfunction
# Python 3 compatibility # Python 3 compatibility
try: try:
@@ -19,6 +21,14 @@ except NameError:
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@contextfunction
def url_static_offline(context, value):
request_parts = os.path.split(os.path.dirname(context.name))
static_path = '/'.join(request_parts[1:])
return url_for('static', filename="%s/%s" % (static_path, value))
def url_for_field(field, value): def url_for_field(field, value):
args = request.view_args.copy() args = request.view_args.copy()
args.update(request.args.copy()) args.update(request.args.copy())

View File

@@ -266,6 +266,9 @@ def test_offline_mode(client, mocker):
assert soup.title.contents[0] == 'Puppetboard' assert soup.title.contents[0] == 'Puppetboard'
for link in soup.find_all('link'): for link in soup.find_all('link'):
assert "//" not in link['href'] assert "//" not in link['href']
if 'offline' in link['href']:
static_rv = client.get(link['href'])
assert rv.status_code == 200
for script in soup.find_all('script'): for script in soup.find_all('script'):
if "src" in script.attrs: if "src" in script.attrs:
@@ -821,3 +824,16 @@ def test_node_facts_json(client, mocker,
assert len(line) == 2 assert len(line) == 2
assert 'chart' not in result_json assert 'chart' not in result_json
def test_offline_static(client):
rv = client.get('/offline/css/google_fonts.css')
assert 'Content-Type' in rv.headers
assert 'text/css' in rv.headers['Content-Type']
assert rv.status_code == 200
rv = client.get('/offline/Semantic-UI-2.1.8/semantic.min.css')
assert 'Content-Type' in rv.headers
assert 'text/css' in rv.headers['Content-Type']
assert rv.status_code == 200