diff --git a/fireworks/__init__.py b/fireworks/__init__.py index c4063cea9..3eb0f3900 100644 --- a/fireworks/__init__.py +++ b/fireworks/__init__.py @@ -3,6 +3,10 @@ __version__ = "1.9.8" FW_INSTALL_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +import warnings +warnings.filterwarnings("ignore", message="numpy.dtype size changed") +warnings.filterwarnings("ignore", message="numpy.ndarray size changed") + # These imports allow a much simpler import of core Fireworks functionality. # E.g., you can now do "from fireworks import Firework", instead of from # "fireworks.core.firework import Firework". diff --git a/fireworks/flask_site/app.py b/fireworks/flask_site/app.py index 660ade93f..e676df975 100644 --- a/fireworks/flask_site/app.py +++ b/fireworks/flask_site/app.py @@ -25,7 +25,20 @@ from fireworks.utilities.fw_serializers import DATETIME_HANDLER from fireworks.utilities.fw_utilities import get_fw_logger +from flask import Blueprint +tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates') +stat_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static') +main_bp = Blueprint('fw_webgui_main', __name__, template_folder=tmpl_dir, static_folder=stat_dir) + + app = Flask(__name__) + + +# Allow application to run under a service prefix url +if os.environ.get("FW_APPLICATION_ROOT"): + app.config["APPLICATION_ROOT"] = os.environ.get("FW_APPLICATION_ROOT") + + app.use_reloader = True app.secret_key = os.environ.get("FWAPP_SECRET_KEY", os.urandom(24)) @@ -87,7 +100,7 @@ def _addq_WF(q): return {"$and": [q, app.BASE_Q_WF, session.get("wf_filt", {}), filt_from_fw]} -@app.template_filter("datetime") +@main_bp.app_template_filter("datetime") def datetime(value): import datetime as dt @@ -95,7 +108,7 @@ def datetime(value): return date.strftime("%m/%d/%Y") -@app.template_filter("pluralize") +@main_bp.template_filter("pluralize") def pluralize(number, singular="", plural="s"): if number == 1: return singular @@ -103,7 +116,7 @@ def pluralize(number, singular="", plural="s"): return plural -@app.route("/") +@main_bp.route("/") @requires_auth def home(): fw_querystr = request.args.get("fw_query") @@ -153,7 +166,7 @@ def home(): return render_template("home.html", **locals()) -@app.route("/fw//details") +@main_bp.route("/fw//details") @requires_auth def get_fw_details(fw_id): # just fill out whatever attributse you want to see per step, then edit the handlebars template in @@ -166,7 +179,7 @@ def get_fw_details(fw_id): return jsonify(fw) -@app.route("/fw/") +@main_bp.route("/fw/") @requires_auth def fw_details(fw_id): try: @@ -178,7 +191,7 @@ def fw_details(fw_id): return render_template("fw_details.html", **locals()) -@app.route("/wf//json") +@main_bp.route("/wf//json") @requires_auth def workflow_json(wf_id): try: @@ -208,7 +221,7 @@ def workflow_json(wf_id): return jsonify(nodes_and_edges) -@app.route("/wf/") +@main_bp.route("/wf/") @requires_auth def wf_details(wf_id): try: @@ -221,9 +234,9 @@ def wf_details(wf_id): return render_template("wf_details.html", **locals()) -@app.route("/fw/", defaults={"state": "total"}) -@app.route("/fw//", defaults={"sorting_key": "_id", "sorting_order": "DESCENDING"}) -@app.route("/fw////") +@main_bp.route("/fw/", defaults={"state": "total"}) +@main_bp.route("/fw//", defaults={"sorting_key": "_id", "sorting_order": "DESCENDING"}) +@main_bp.route("/fw////") @requires_auth def fw_state(state, sorting_key="_id", sorting_order="DESCENDING"): if sorting_order == "ASCENDING": @@ -253,9 +266,9 @@ def fw_state(state, sorting_key="_id", sorting_order="DESCENDING"): return render_template("fw_state.html", **locals()) -@app.route("/wf/", defaults={"state": "total"}) -@app.route("/wf//", defaults={"sorting_key": "_id", "sorting_order": "DESCENDING"}) -@app.route("/wf////") +@main_bp.route("/wf/", defaults={"state": "total"}) +@main_bp.route("/wf//", defaults={"sorting_key": "_id", "sorting_order": "DESCENDING"}) +@main_bp.route("/wf////") @requires_auth def wf_state(state, sorting_key="_id", sorting_order="DESCENDING"): if sorting_order == "ASCENDING": @@ -281,8 +294,8 @@ def wf_state(state, sorting_key="_id", sorting_order="DESCENDING"): return render_template("wf_state.html", **locals()) -@app.route("/wf/metadata///", defaults={"state": "total"}) -@app.route("/wf/metadata////") +@main_bp.route("/wf/metadata///", defaults={"state": "total"}) +@main_bp.route("/wf/metadata////") @requires_auth def wf_metadata_find(key, value, state): db = app.lp.workflows @@ -314,9 +327,9 @@ def wf_metadata_find(key, value, state): return render_template("wf_metadata.html", **locals()) -@app.route("/report/", defaults={"interval": "months", "num_intervals": 6}) -@app.route("/report//", defaults={"num_intervals": 6}) -@app.route("/report///") +@main_bp.route("/report/", defaults={"interval": "months", "num_intervals": 6}) +@main_bp.route("/report//", defaults={"num_intervals": 6}) +@main_bp.route("/report///") @requires_auth def report(interval, num_intervals): num_intervals = int(num_intervals) @@ -341,7 +354,7 @@ def report(interval, num_intervals): return render_template("report.html", **locals()) -@app.route("/dashboard/") +@main_bp.route("/dashboard/") @requires_auth def dashboard(): PLOTTING = False @@ -375,7 +388,7 @@ def parse_querystr(querystr, coll): return d -@app.route("/reports////fig.png") +@main_bp.route("/reports////fig.png") def simple(coll, interval, num_intervals): from io import BytesIO @@ -391,6 +404,8 @@ def simple(coll, interval, num_intervals): response.headers["Content-Type"] = "image/png" return response +app.register_blueprint(main_bp, url_prefix=app.config["APPLICATION_ROOT"]) + if __name__ == "__main__": app.run(debug=True, port=8080) diff --git a/fireworks/flask_site/static/js/wf_cyto.js b/fireworks/flask_site/static/js/wf_cyto.js index d7b3673c9..c8beff398 100644 --- a/fireworks/flask_site/static/js/wf_cyto.js +++ b/fireworks/flask_site/static/js/wf_cyto.js @@ -1,79 +1,78 @@ $(document).ready(function() { var options = { - name: 'dagre', + name: 'dagre', - // dagre algo options, uses default value on undefined - nodeSep: undefined, // the separation between adjacent nodes in the same rank - edgeSep: undefined, // the separation between adjacent edges in the same rank - rankSep: undefined, // the separation between adjacent nodes in the same rank - rankDir: 'TB', // 'TB' for top to bottom flow, 'LR' for left to right - minLen: function( edge ){ return 1; }, // number of ranks to keep between the source and target of the edge - edgeWeight: function( edge ){ return 1; }, // higher weight edges are generally made shorter and straighter than lower weight edges + // dagre algo options, uses default value on undefined + nodeSep: undefined, // the separation between adjacent nodes in the same rank + edgeSep: undefined, // the separation between adjacent edges in the same rank + rankSep: undefined, // the separation between adjacent nodes in the same rank + rankDir: 'TB', // 'TB' for top to bottom flow, 'LR' for left to right + minLen: function( edge ){ return 1; }, // number of ranks to keep between the source and target of the edge + edgeWeight: function( edge ){ return 1; }, // higher weight edges are generally made shorter and straighter than lower weight edges - // general layout options - fit: true, // whether to fit to viewport - padding: 30, // fit padding - animate: false, // whether to transition the node positions - animationDuration: 500, // duration of animation in ms if enabled - boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } - ready: function(){}, // on layoutready - stop: function(){} // on layoutstop -}; - $.getJSON("/wf/"+ $("#wf_id").html()+ "/json", function(result){ + // general layout options + fit: true, // whether to fit to viewport + padding: 30, // fit padding + animate: false, // whether to transition the node positions + animationDuration: 500, // duration of animation in ms if enabled + boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + ready: function(){}, // on layoutready + stop: function(){} // on layoutstop + }; + var wf_json = window.location.pathname + "/json"; + $.getJSON(wf_json, function(result){ var cy = cytoscape({ -container: document.getElementById('cy'), -style: cytoscape.stylesheet() - .selector('node') - .css({ - 'content': 'data(name)', - 'text-valign': 'center', - 'width':'data(width)', - 'shape':'rectangle', - 'color': 'white', - 'background-color' : 'data(state)', - 'text-outline-width': 1, - 'font-family': "Open Sans, sans-serif", - 'font-size': 14, - 'text-outline-color': '#888' - }) - .selector('edge') - .css({ - 'target-arrow-shape': 'triangle' - }) - .selector(':selected') - .css({ - 'background-color': 'black', - 'line-color': 'black', - 'target-arrow-color': 'black', - 'source-arrow-color': 'black' - }) - .selector('.faded') - .css({ - 'opacity': 0.25, - 'text-opacity': 0 - }), - elements: { - nodes:result.nodes, - edges:result.edges, - }, - ready: function() { - window.cy = this; - cy.layout(options); - cy.panzoom(); - } -}); - $('#json').JSONView('collapse') -var source = $("#job-details").html(); -var template = Handlebars.compile(source); -cy.on("click", 'node', function(evt) { - $.getJSON("/fw/" + this.data('id') + "/details", function(result) { + container: document.getElementById('cy'), + style: cytoscape.stylesheet() + .selector('node') + .css({ + 'content': 'data(name)', + 'text-valign': 'center', + 'width':'data(width)', + 'shape':'rectangle', + 'color': 'white', + 'background-color' : 'data(state)', + 'text-outline-width': 1, + 'font-family': "Open Sans, sans-serif", + 'font-size': 14, + 'text-outline-color': '#888' + }) + .selector('edge') + .css({ + 'target-arrow-shape': 'triangle' + }) + .selector(':selected') + .css({ + 'background-color': 'black', + 'line-color': 'black', + 'target-arrow-color': 'black', + 'source-arrow-color': 'black' + }) + .selector('.faded') + .css({ + 'opacity': 0.25, + 'text-opacity': 0 + }), + elements: { + nodes:result.nodes, + edges:result.edges, + }, + ready: function() { + window.cy = this; + cy.layout(options); + cy.panzoom(); + } + }); + $('#json').JSONView('collapse') + var source = $("#job-details").html(); + var template = Handlebars.compile(source); + cy.on("click", 'node', function(evt) { + var path = window.location.pathname.split('/'); + var root = path.splice(0, path.length-2).join('/'); + $.getJSON(root + "/fw/" + this.data('id') + "/details", function(result) { $("#job-details-target").html(template(result)); }); }); -}); - - - - + }); }); diff --git a/fireworks/flask_site/templates/base.html b/fireworks/flask_site/templates/base.html index 5e078f65d..38c64841b 100644 --- a/fireworks/flask_site/templates/base.html +++ b/fireworks/flask_site/templates/base.html @@ -1,9 +1,9 @@ - - - + + + {% block morehead %}{% endblock %} {% block title %}{% endblock %} @@ -11,8 +11,8 @@
diff --git a/fireworks/flask_site/templates/dashboard.html b/fireworks/flask_site/templates/dashboard.html index f2b9a7f78..7a93cb8cc 100644 --- a/fireworks/flask_site/templates/dashboard.html +++ b/fireworks/flask_site/templates/dashboard.html @@ -6,18 +6,18 @@

Fireworks

{% if PLOTTING %}
- +
- +
- +
- +
{% else %} @@ -30,18 +30,18 @@

Workflows

{% if PLOTTING %}
- +
- +
- +
- +
{% else %} diff --git a/fireworks/flask_site/templates/fw_details.html b/fireworks/flask_site/templates/fw_details.html index 929f192c9..90d2fd55d 100644 --- a/fireworks/flask_site/templates/fw_details.html +++ b/fireworks/flask_site/templates/fw_details.html @@ -3,9 +3,9 @@ {% block title %}Firework {{ fw_id }} Details{% endblock %} {% block morehead %} - + - + - - - - - - + + + + + + {% raw %}