Skip to content

Commit

Permalink
Merge pull request #160 from DigiKlausur/diagram_editor
Browse files Browse the repository at this point in the history
Diagram editor
  • Loading branch information
tmetzl authored Sep 1, 2023
2 parents 8ce5ef5 + 9495fdc commit f193007
Show file tree
Hide file tree
Showing 11 changed files with 445 additions and 361 deletions.
5 changes: 5 additions & 0 deletions docs/source/extensions/apps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,15 @@ Let's start by looking at the file `app.py`.
},
).tag(config=True)
def __init__(self, **kwargs):
NbGrader.__init__(self, **kwargs)
BaseApp.__init__(self, **kwargs)
template_path = os.path.join(os.path.dirname(__file__), "templates")
def load_app(self):
self.log.info("Loading the convert grades app")
self.initialize([])
# Add the grading scheme to the tornado settings
self.update_tornado_settings(dict(e2x_grading_scheme=self.grading_scheme))
self.add_handlers(default_handlers)
Expand Down
18 changes: 18 additions & 0 deletions docs/source/user_docs/cells/cells.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ In student mode the `Edit Cell` button is deactivated and students can not unren

.. _diagrams.net: https://diagrams.net

Configuring the Diagram Cells
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can configure the following options for the diagram cells in your ``nbgrader_config.py``:

* ``drawDomain``: The domain of the diagram instance to use
* ``drawOrigin``: The url of the origin of the diagram instance. This is the url from which the diagram instance sends messages
* ``libraries``: A list of libraries which should be active by default (e.g. *uml*, *general*, *kubernetes*, etc)

.. code-block:: python
:caption: Example of configuring the diagram editor
# nbgrader_config.py
c.DiagramEditor.drawDomain = "https://embed.diagrams.net/"
c.DiagramEditor.drawOrigin = "https://embed.diagrams.net/"
c.DiagramEditor.libraries = ["uml", "general", "arrows2"]
Upload Cells
------------
Expand Down
3 changes: 3 additions & 0 deletions e2xgrader/server_extensions/apps/diagram_editor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .diagrameditor import DiagramEditor

__all__ = ["DiagramEditor"]
52 changes: 52 additions & 0 deletions e2xgrader/server_extensions/apps/diagram_editor/diagrameditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import json

from e2xcore import BaseApp
from e2xcore.handlers import E2xApiHandler
from nbgrader.apps.baseapp import NbGrader
from nbgrader.server_extensions.formgrader.base import check_xsrf
from tornado import web
from traitlets import List, Unicode


class DiagramConfigHandler(E2xApiHandler):
@web.authenticated
@check_xsrf
def get(self):
self.finish(json.dumps(self.settings.get("diagram_config", dict())))


class DiagramEditor(NbGrader, BaseApp):
drawDomain = Unicode(
default_value=None, allow_none=True, help="The url to drawio"
).tag(config=True)
drawOrigin = Unicode(
default_value=None, allow_none=True, help="The drawio origin"
).tag(config=True)
libraries = List(default_value=[], help="A list of activated libraries").tag(
config=True
)

def __init__(self, **kwargs):
NbGrader.__init__(self, **kwargs)
BaseApp.__init__(self, **kwargs)

def get_diagram_config(self):
# self.log.info("My drawDomain is", self.drawDomain)
config = dict()
if self.drawDomain:
config["drawDomain"] = self.drawDomain
if self.drawOrigin:
config["drawOrigin"] = self.drawOrigin
if len(self.libraries) > 0:
config["libs"] = self.libraries
return config

def load_app(self):
self.log.info("Loading the diagrameditor app")
self.initialize([])
self.update_tornado_settings(dict(diagram_config=self.get_diagram_config()))
self.add_handlers(
[
(r"/e2x/diagrams/api", DiagramConfigHandler),
]
)
3 changes: 2 additions & 1 deletion e2xgrader/server_extensions/student/student.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from traitlets import Any, List

from ..apps.assignment_list import AssignmentList
from ..apps.diagram_editor import DiagramEditor
from ..apps.help import Help
from ..apps.validate_assignment import ValidateAssignment
from ..base import BaseExtension
Expand All @@ -9,7 +10,7 @@
class StudentExtension(BaseExtension):
apps = List(
trait=Any(),
default_value=[AssignmentList, ValidateAssignment, Help],
default_value=[AssignmentList, ValidateAssignment, Help, DiagramEditor],
).tag(config=True)


Expand Down
2 changes: 2 additions & 0 deletions e2xgrader/server_extensions/teacher/teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from traitlets import Any, List

from ..apps.assignment_list import AssignmentList
from ..apps.diagram_editor import DiagramEditor
from ..apps.e2xgraderapi import E2xGraderApi
from ..apps.formgrader import FormgradeApp
from ..apps.help import Help
Expand All @@ -21,6 +22,7 @@ class TeacherExtension(BaseExtension):
ValidateAssignment,
AssignmentList,
Help,
DiagramEditor,
],
).tag(config=True)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import unittest

from traitlets.config import LoggingConfigurable

from e2xgrader.server_extensions.apps.diagram_editor import DiagramEditor


class DummyWebApp:
@property
def settings(self):
return dict()


class DummyApp(LoggingConfigurable):
root_dir = "dummy"
name = "dummy"

@property
def web_app(self):
return DummyWebApp()


class TestDiagramEditor(unittest.TestCase):
def setUp(self) -> None:
self.editor = DiagramEditor(parent=DummyApp())

def test_empty_config(self):
self.assertDictEqual(self.editor.get_diagram_config(), dict())

def test_configure_draw_domain(self):
domain = "myDomain"
self.editor.drawDomain = domain
self.assertDictEqual(self.editor.get_diagram_config(), dict(drawDomain=domain))

def test_configure_draw_origin(self):
domain = "myDomain"
self.editor.drawOrigin = domain
self.assertDictEqual(self.editor.get_diagram_config(), dict(drawOrigin=domain))

def test_configure_libraries(self):
libraries = ["lib1", "lib2", "lib3"]
self.editor.libraries = libraries
self.assertDictEqual(self.editor.get_diagram_config(), dict(libs=libraries))

def tearDown(self) -> None:
self.editor.drawDomain = None
self.editor.drawOrigin = None
self.editor.libraries = []
4 changes: 4 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/cells/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
},
"author": "Tim Metzler",
"license": "ISC",
"dependencies": {
"@e2xgrader/api": "0.1.1"
},
"devDependencies": {
"@babel/preset-env": "^7.16.11",
"css-loader": "^6.6.0",
Expand Down
11 changes: 9 additions & 2 deletions packages/cells/src/cells/diagram-cell.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { E2xCell } from "./base";
import { AttachmentModel } from "../utils/attachment-model";
import { DiagramEditor } from "../utils/diagram-editor";
import DiagramEditor from "../utils/diagram-editor";

class DiagramCellModel extends AttachmentModel {
postSaveHook() {
Expand Down Expand Up @@ -56,7 +56,14 @@ export class DiagramCell extends E2xCell {
let button = $("<button/>")
.append("Edit Diagram")
.addClass("btn-e2x btn-diagram");
button.on("click", () => DiagramEditor.editElement(that, img[0]));

button.on("click", async () => {
try {
await DiagramEditor.editDiagram(that, img[0]);
} catch (error) {
console.error("Failed to load DiagramEditor:", error);
}
});

html.append(img);
html.append(button);
Expand Down
Loading

0 comments on commit f193007

Please sign in to comment.