Improved navigation and clarity in details view.

This commit is contained in:
lwark
2024-09-13 15:23:11 -05:00
parent 744394f236
commit c7d83401e7
15 changed files with 270 additions and 177 deletions

View File

@@ -1,14 +1,16 @@
"""
Webview to show submission and sample details.
"""
from PyQt6.QtWidgets import (QDialog, QPushButton, QVBoxLayout,
QDialogButtonBox, QTextEdit)
from PyQt6.QtGui import QColor
from PyQt6.QtWidgets import (QDialog, QPushButton, QVBoxLayout,
QDialogButtonBox, QTextEdit, QGridLayout)
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebChannel import QWebChannel
from PyQt6.QtCore import Qt, pyqtSlot
from jinja2 import TemplateNotFound
from backend.db.models import BasicSubmission, BasicSample
from tools import is_power_user, html_to_pdf
from backend.db.models import BasicSubmission, BasicSample, Reagent, KitType
from tools import is_power_user, html_to_pdf, jinja_template_loading
from .functions import select_save_file
from pathlib import Path
import logging
@@ -25,8 +27,9 @@ logger = logging.getLogger(f"submissions.{__name__}")
class SubmissionDetails(QDialog):
"""
a window showing text details of submission
"""
def __init__(self, parent, sub:BasicSubmission|BasicSample) -> None:
"""
def __init__(self, parent, sub: BasicSubmission | BasicSample | Reagent) -> None:
super().__init__(parent)
try:
@@ -35,15 +38,20 @@ class SubmissionDetails(QDialog):
self.app = None
self.webview = QWebEngineView(parent=self)
self.webview.setMinimumSize(900, 500)
self.webview.setMaximumSize(900, 500)
self.layout = QVBoxLayout()
self.setFixedSize(900, 500)
self.webview.setMaximumSize(900, 700)
self.webview.loadFinished.connect(self.activate_export)
self.layout = QGridLayout()
# self.setFixedSize(900, 500)
# NOTE: button to export a pdf version
btn = QPushButton("Export DOCX")
btn.setFixedWidth(875)
btn.clicked.connect(self.export)
self.layout.addWidget(btn)
self.layout.addWidget(self.webview)
self.btn = QPushButton("Export DOCX")
self.btn.setFixedWidth(775)
self.btn.clicked.connect(self.export)
self.back = QPushButton("Back")
self.back.setFixedWidth(100)
self.back.clicked.connect(self.back_function)
self.layout.addWidget(self.back, 0, 0, 1, 1)
self.layout.addWidget(self.btn, 0, 1, 1, 9)
self.layout.addWidget(self.webview, 1, 0, 10, 10)
self.setLayout(self.layout)
# NOTE: setup channel
self.channel = QWebChannel()
@@ -54,10 +62,26 @@ class SubmissionDetails(QDialog):
self.rsl_plate_num = sub.rsl_plate_num
case BasicSample():
self.sample_details(sample=sub)
case Reagent():
self.reagent_details(reagent=sub)
self.webview.page().setWebChannel(self.channel)
def back_function(self):
self.webview.back()
# @pyqtSlot(bool)
def activate_export(self):
title = self.webview.title()
self.setWindowTitle(title)
if "Submission" in title:
self.btn.setEnabled(True)
self.export_plate = title.split(" ")[-1]
logger.debug(f"Updating export plate to: {self.export_plate}")
else:
self.btn.setEnabled(False)
@pyqtSlot(str)
def sample_details(self, sample:str|BasicSample):
def sample_details(self, sample: str | BasicSample):
"""
Changes details view to summary of Sample
@@ -68,21 +92,49 @@ class SubmissionDetails(QDialog):
sample = BasicSample.query(submitter_id=sample)
base_dict = sample.to_sub_dict(full_data=True)
base_dict, template = sample.get_details_template(base_dict=base_dict)
html = template.render(sample=base_dict)
template_path = Path(self.template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
css = f.read()
html = template.render(sample=base_dict, css=css)
self.webview.setHtml(html)
self.setWindowTitle(f"Sample Details - {sample.submitter_id}")
# self.btn.setEnabled(False)
@pyqtSlot(str, str)
def reagent_details(self, reagent: str | Reagent, kit: str | KitType):
if isinstance(reagent, str):
reagent = Reagent.query(lot_number=reagent)
if isinstance(kit, str):
kit = KitType.query(name=kit)
base_dict = reagent.to_sub_dict(extraction_kit=kit, full_data=True)
env = jinja_template_loading()
temp_name = "reagent_details.html"
# logger.debug(f"Returning template: {temp_name}")
try:
template = env.get_template(temp_name)
except TemplateNotFound as e:
logger.error(f"Couldn't find template due to {e}")
return
template_path = Path(self.template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
css = f.read()
html = template.render(reagent=base_dict, css=css)
self.webview.setHtml(html)
self.setWindowTitle(f"Reagent Details - {reagent.name} - {reagent.lot}")
# self.btn.setEnabled(False)
@pyqtSlot(str)
def submission_details(self, submission:str|BasicSubmission):
def submission_details(self, submission: str | BasicSubmission):
"""
Sets details view to summary of Submission.
Args:
submission (str | BasicSubmission): Submission of interest.
"""
"""
# logger.debug(f"Details for: {submission}")
if isinstance(submission, str):
submission = BasicSubmission.query(rsl_plate_num=submission)
self.rsl_plate_num = submission.rsl_plate_num
self.base_dict = submission.to_dict(full_data=True)
# logger.debug(f"Submission details data:\n{pformat({k:v for k,v in self.base_dict.items() if k == 'reagents'})}")
# NOTE: don't want id
@@ -97,10 +149,10 @@ class SubmissionDetails(QDialog):
# logger.debug(f"Submission_details: {pformat(self.base_dict)}")
self.html = self.template.render(sub=self.base_dict, signing_permission=is_power_user(), css=css)
self.webview.setHtml(self.html)
self.setWindowTitle(f"Submission Details - {submission.rsl_plate_num}")
# self.btn.setEnabled(True)
@pyqtSlot(str)
def sign_off(self, submission:str|BasicSubmission):
def sign_off(self, submission: str | BasicSubmission):
# logger.debug(f"Signing off on {submission} - ({getuser()})")
if isinstance(submission, str):
submission = BasicSubmission.query(rsl_plate_num=submission)
@@ -112,19 +164,23 @@ class SubmissionDetails(QDialog):
"""
Renders submission to html, then creates and saves .pdf file to user selected file.
"""
writer = DocxWriter(base_dict=self.base_dict)
fname = select_save_file(obj=self, default_name=self.base_dict['plate_number'], extension="docx")
export_plate = BasicSubmission.query(rsl_plate_num=self.export_plate)
base_dict = export_plate.to_dict(full_data=True)
writer = DocxWriter(base_dict=base_dict)
fname = select_save_file(obj=self, default_name=base_dict['plate_number'], extension="docx")
writer.save(fname)
try:
html_to_pdf(html=self.html, output_file=fname)
except PermissionError as e:
logger.error(f"Error saving pdf: {e}")
class SubmissionComment(QDialog):
"""
a window for adding comment text to a submission
"""
def __init__(self, parent, submission:BasicSubmission) -> None:
"""
def __init__(self, parent, submission: BasicSubmission) -> None:
super().__init__(parent)
try:
@@ -137,7 +193,8 @@ class SubmissionComment(QDialog):
# NOTE: create text field
self.txt_editor = QTextEdit(self)
self.txt_editor.setReadOnly(False)
self.txt_editor.setText("Add Comment")
self.txt_editor.setPlaceholderText("Write your comment here.")
self.txt_editor.setStyleSheet("background-color: rgb(255, 255, 255);")
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
@@ -147,14 +204,16 @@ class SubmissionComment(QDialog):
self.layout.addWidget(self.txt_editor)
self.layout.addWidget(self.buttonBox, alignment=Qt.AlignmentFlag.AlignBottom)
self.setLayout(self.layout)
def parse_form(self) -> List[dict]:
"""
Adds comment to submission object.
"""
"""
commenter = getuser()
comment = self.txt_editor.toPlainText()
if comment in ["", None]:
return None
dt = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
full_comment = {"name":commenter, "time": dt, "text": comment}
full_comment = {"name": commenter, "time": dt, "text": comment}
# logger.debug(f"Full comment: {full_comment}")
return full_comment