Explorar el Código

Add optional config dictionary to mermaid component to be passed initialize() on mount (#3164)

* Add optional config dictionary to mermaid component to be passed initialize() on mount

* code review, simplify tests

* add documentation

---------

Co-authored-by: Ian Bottomley <ian@kyloe.net>
Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Ian Bottomley hace 11 meses
padre
commit
5fc7c4478e

+ 10 - 0
nicegui/elements/mermaid.js

@@ -9,9 +9,18 @@ export default {
     last_content: "",
   }),
   mounted() {
+    this.initialize();
     this.update(this.content);
   },
   methods: {
+    initialize() {
+      try {
+        mermaid.initialize(this.config || {});
+      } catch (error) {
+        console.error(error);
+        this.$emit("error", error);
+      }
+    },
     async update(content) {
       if (this.last_content === content) return;
       this.last_content = content;
@@ -32,6 +41,7 @@ export default {
     },
   },
   props: {
+    config: Object,
     content: String,
   },
 };

+ 13 - 1
nicegui/elements/mermaid.py

@@ -1,3 +1,5 @@
+from typing import Dict, Optional
+
 from .mixins.content_element import ContentElement
 
 
@@ -7,15 +9,25 @@ class Mermaid(ContentElement,
               extra_libraries=['lib/mermaid/*.js']):
     CONTENT_PROP = 'content'
 
-    def __init__(self, content: str) -> None:
+    def __init__(self, content: str, config: Optional[Dict] = None) -> None:
         """Mermaid Diagrams
 
         Renders diagrams and charts written in the Markdown-inspired `Mermaid <https://mermaid.js.org/>`_ language.
         The mermaid syntax can also be used inside Markdown elements by providing the extension string 'mermaid' to the ``ui.markdown`` element.
 
+        The optional configuration dictionary is passed directly to mermaid before the first diagram is rendered.
+        This can be used to set such options as
+
+            ``{'securityLevel': 'loose', ...}`` - allow running JavaScript when a node is clicked
+            ``{'logLevel': 'info', ...}`` - log debug info to the console
+
+        Refer to the Mermaid documentation for the ``mermaid.initialize()`` method for a full list of options.
+
         :param content: the Mermaid content to be displayed
+        :param config: configuration dictionary to be passed to ``mermaid.initialize()``
         """
         super().__init__(content=content)
+        self._props['config'] = config
 
     def _handle_content_change(self, content: str) -> None:
         self._props[self.CONTENT_PROP] = content.strip()

+ 19 - 0
tests/test_mermaid.py

@@ -1,3 +1,5 @@
+import pytest
+
 from nicegui import ui
 from nicegui.testing import Screen
 
@@ -75,3 +77,20 @@ def test_error(screen: Screen):
     screen.open('/')
     screen.should_contain('Syntax error in text')
     screen.should_contain('Parse error on line 3')
+
+
+@pytest.mark.parametrize('security_level', ['loose', 'strict'])
+def test_click_mermaid_node(security_level: str, screen: Screen):
+    ui.mermaid('''
+        flowchart TD;
+            A;
+            click A call document.write("Success")
+    ''', config={'securityLevel': security_level})
+
+    screen.open('/')
+    screen.click('A')
+    screen.wait(0.5)
+    if security_level == 'loose':
+        screen.should_contain('Success')
+    else:
+        screen.should_not_contain('Success')

+ 17 - 0
website/documentation/content/mermaid_documentation.py

@@ -10,6 +10,21 @@ def main_demo() -> None:
         A --> B;
         A --> C;
     ''')
+    # END OF DEMO
+    list(ui.context.client.elements.values())[-1]._props['config'] = {'securityLevel': 'loose'}  # HACK: for click_demo
+
+
+@doc.demo('Handle click events', '''
+    You can register to click events by adding a `click` directive to a node and emitting a custom event.
+    Make sure to set the `securityLevel` to `loose` in the `config` parameter to allow JavaScript execution.
+''')
+def click_demo() -> None:
+    ui.mermaid('''
+    graph LR;
+        A((Click me!));
+        click A call emitEvent("mermaid_click", "You clicked me!")
+    ''', config={'securityLevel': 'loose'})
+    ui.on('mermaid_click', lambda e: ui.notify(e.args))
 
 
 @doc.demo('Handle errors', '''
@@ -22,6 +37,8 @@ def error_demo() -> None:
         A --> B;
         A -> C;
     ''').on('error', lambda e: print(e.args['message']))
+    # END OF DEMO
+    list(ui.context.client.elements.values())[-1]._props['config'] = {'securityLevel': 'loose'}  # HACK: for click_demo
 
 
 doc.reference(ui.mermaid)