Source code for signac_dashboard.modules.document_editor

# Copyright (c) 2022 The Regents of the University of Michigan
# All rights reserved.
# This software is licensed under the BSD 3-Clause License.
from ast import literal_eval
from collections import OrderedDict

import flask_login
from flask import abort, render_template, request
from jinja2.exceptions import TemplateNotFound
from markupsafe import escape

from signac_dashboard.module import Module


[docs]class DocumentEditor(Module): """Provides an interface to edit the job document. This module shows keys in the job document with a form that allows users to edit their contents. When saving, the edited strings are parsed into JSON-compatible Python data structures (e.g., :py:class:`list` and :py:class:`dict`). Job document keys beginning with an underscore :code:`_` are treated as private and are not displayed. :param context: Supports :code:`'JobContext'`. :type context: str """ _supported_contexts = {"JobContext"} def __init__( self, name="Document Editor", context="JobContext", template="cards/document_editor.html", **kwargs, ): super().__init__( name=name, context=context, template=template, **kwargs, ) def get_cards(self, job): doc = OrderedDict(sorted(job.document.items(), key=lambda t: t[0])) for key in doc: if key.startswith("_"): # Don't allow users to edit "private" keys that begin with _ del doc[key] else: doc[key] = escape(repr(doc[key])) return [ { "name": self.name, "content": render_template(self.template, document=doc, jobid=job._id), } ] def register(self, dashboard): # Register routes @dashboard.app.route("/module/document_editor/update", methods=["POST"]) @flask_login.login_required def document_editor_update(): jobid = request.form.get("jobid") job = dashboard.project.open_job(id=jobid) for key, value in request.form.items(): if key.startswith("doc:"): key = key[4:] try: job.doc[key] = literal_eval(value) except (SyntaxError, TypeError, ValueError) as e: return ( f"Error in key <strong>{key}</strong>: {e}", 422, ) return "Saved." @dashboard.app.route("/module/document_editor/<path:filename>") @flask_login.login_required def document_editor_asset(filename): path = f"document_editor/{filename}" try: return render_template(path) except TemplateNotFound: abort(404, "The file requested does not exist.") # Register assets assets = ["js/document_editor.js"] for assetfile in assets: dashboard.register_module_asset( { "file": f"templates/document_editor/{assetfile}", "url": f"/module/document_editor/{assetfile}", } )