]> Softwares of Agnibho - medscript.git/commitdiff
Web App Plugin
authorAgnibho Mondal <mondal@agnibho.com>
Sun, 12 Nov 2023 12:38:09 +0000 (18:08 +0530)
committerAgnibho Mondal <mondal@agnibho.com>
Sun, 12 Nov 2023 12:38:09 +0000 (18:08 +0530)
README
plugin.py
window.py

diff --git a/README b/README
index b8868f12221220eaabdd45cdf8b1c053dd3bb7cb..19eb119302935a64a94663e8c749e911508135d2 100644 (file)
--- a/README
+++ b/README
@@ -424,6 +424,15 @@ An example plugin, that modifies the name of the patient, may be as follows:
         global text
         text=data.strip()
 
+Plugins may also contain a web app written in HTML/JavaScript. To use it the
+plugin must contain a function called `web` which takes the prescription object
+and returns the URL of the web app. The run function of such a plugin must
+take two arguments, the prescription and the data returned from the web app.
+
+The web app itself must include the qtwebchannel.js from PyQt6. The webchannel
+exposes an object named `js` to the web app. The web app may return data by
+calling the `run` function of the exposed `js` object.
+
 Template Development
 --------------------
 
index eb4fb18cb4832200224ee365479619bddf0a3509..44a100c759b7a603e0568ae3ea28df38459c7813 100644 (file)
--- a/plugin.py
+++ b/plugin.py
@@ -6,18 +6,24 @@
 # You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
 
 import logging, os, importlib, copy
-from PyQt6.QtWidgets import QMessageBox, QInputDialog, QFileDialog
-from PyQt6.QtCore import QThread, pyqtSignal
+from PyQt6.QtWidgets import QMessageBox, QMainWindow, QInputDialog, QFileDialog, QVBoxLayout
+from PyQt6.QtCore import QObject, QThread, QUrl, pyqtSignal, pyqtSlot
+from PyQt6.QtWebChannel import QWebChannel
+from PyQt6.QtGui import QIcon
+from PyQt6.QtWebEngineWidgets import QWebEngineView
 from glob import glob
 from config import config
 
-class Plugin():
+class Plugin(QObject):
+
+    update=pyqtSignal()
 
     plugins=[]
     names=[]
     workers=[]
 
     def __init__(self):
+        super().__init__()
         if(config["enable_plugin"]):
             self.load()
 
@@ -96,7 +102,13 @@ class Plugin():
 
     def run(self, module, prescription):
         try:
-            if(hasattr(module, "run") and callable(module.run)):
+            if(hasattr(module, "web") and callable(module.web)):
+                    self.webapp=WebApp()
+                    self.webapp.done.connect(lambda: self.update.emit())
+                    url=module.web(prescription)
+                    self.webapp.load(module, QUrl(url), prescription)
+                    self.webapp.show()
+            elif(hasattr(module, "run") and callable(module.run)):
                 if(hasattr(module, "confirm") and module.confirm):
                     if(QMessageBox.StandardButton.Yes!=QMessageBox.question(None,"Confirm", module.confirm)):
                         return
@@ -135,6 +147,49 @@ class Plugin():
         if index is not None:
             self.workers[index]=None
 
+class WebApp(QMainWindow):
+
+    done=pyqtSignal()
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        self.setWindowTitle("WebApp Plugin")
+        self.setGeometry(100, 100, 400, 400)
+        self.setWindowIcon(QIcon(os.path.join("resource", "icon_medscript.ico")))
+
+        self.webview=QWebEngineView()
+        self.setCentralWidget(self.webview)
+
+    def load(self, module, url, prescription):
+        self.module=module
+        self.webview.load(url)
+        self.channel=QWebChannel()
+        self.js=JS(module, prescription)
+        self.channel.registerObject("js", self.js)
+        self.webview.page().setWebChannel(self.channel)
+        self.js.done.connect(lambda: self.done.emit())
+
+class JS(QObject):
+
+    done=pyqtSignal()
+
+    def __init__(self, module, prescription):
+        super().__init__()
+        self.module=module
+        self.prescription=prescription
+
+    @pyqtSlot(str)
+    def run(self, data):
+        try:
+            message=self.module.run(self.prescription, data)
+            if(message):
+                QMessageBox.information(None, "Information", message)
+            self.done.emit()
+        except Exception as e:
+            logging.error(self.module)
+            logging.exception(e)
+
 class Worker(QThread):
 
     pluginComplete=pyqtSignal(str, int)
index 445b06ac86b36fadd37a266b6799edc376c6e774..a5b71cb9813ccccfa1cb86803ab20bfc6902c930 100644 (file)
--- a/window.py
+++ b/window.py
@@ -942,6 +942,7 @@ class MainWindow(QMainWindow):
         self.installer=Installer()
         self.index.signal_open.connect(self.cmd_open)
         self.index.signal_copy.connect(self.cmd_copy)
+        self.plugin.update.connect(lambda: self.load_interface_from_instance())
         self.signal_update.connect(self.show_update)
 
         self.new_doc()