Ui updates.
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
## 202407.05
|
||||||
|
|
||||||
|
- Ui updates.
|
||||||
|
|
||||||
## 202407.04
|
## 202407.04
|
||||||
|
|
||||||
- Added support for postgresql databases (auto backup not functional).
|
- Added support for postgresql databases (auto backup not functional).
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ This is meant to import .xslx files created from the Design & Analysis Software
|
|||||||
|
|
||||||
## First Run:
|
## First Run:
|
||||||
|
|
||||||
1. On first run, the application copies src/config.yml to C:\Users\{USERNAME}\Local\submissions\config
|
1. On first run, the application copies src/config.yml to C:\Users\{USERNAME}\AppData\Local\submissions\config
|
||||||
2. If this folder cannot be found, C:\Users\{USERNAME}\Documents\submissions will be used.
|
2. If this folder cannot be found, C:\Users\{USERNAME}\Documents\submissions will be used.
|
||||||
1. If using Postgres, the 'database_path' and other variables will have to be updated manually.
|
1. If using Postgres, the 'database_path' and other variables will have to be updated manually.
|
||||||
3. Initially, the config variables are set parsing the 'sqlalchemy.url' variable in alembic.ini
|
3. Initially, the config variables are set parsing the 'sqlalchemy.url' variable in alembic.ini
|
||||||
|
|||||||
@@ -824,7 +824,7 @@ class PydSubmission(BaseModel, extra='allow'):
|
|||||||
SubmissionFormWidget: Submission form widget
|
SubmissionFormWidget: Submission form widget
|
||||||
"""
|
"""
|
||||||
from frontend.widgets.submission_widget import SubmissionFormWidget
|
from frontend.widgets.submission_widget import SubmissionFormWidget
|
||||||
logger.debug(f"Disbable: {disable}")
|
# logger.debug(f"Disable: {disable}")
|
||||||
return SubmissionFormWidget(parent=parent, submission=self, disable=disable)
|
return SubmissionFormWidget(parent=parent, submission=self, disable=disable)
|
||||||
|
|
||||||
def to_writer(self) -> "SheetWriter":
|
def to_writer(self) -> "SheetWriter":
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from PyQt6.QtCore import Qt
|
|||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QWidget, QVBoxLayout, QScrollArea,
|
QWidget, QVBoxLayout, QScrollArea,
|
||||||
QGridLayout, QPushButton, QLabel,
|
QGridLayout, QPushButton, QLabel,
|
||||||
QLineEdit, QSpinBox
|
QLineEdit, QSpinBox, QCheckBox
|
||||||
)
|
)
|
||||||
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
||||||
from backend.db import SubmissionType, BasicSubmission
|
from backend.db import SubmissionType, BasicSubmission
|
||||||
@@ -62,7 +62,7 @@ class SubmissionTypeAdder(QWidget):
|
|||||||
ST.template_file = f.read()
|
ST.template_file = f.read()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.error(f"Could not find template file: {self.template_path}")
|
logger.error(f"Could not find template file: {self.template_path}")
|
||||||
ST.save(ctx=self.app.ctx)
|
ST.save()
|
||||||
|
|
||||||
def parse_form(self) -> dict:
|
def parse_form(self) -> dict:
|
||||||
"""
|
"""
|
||||||
@@ -88,7 +88,10 @@ class InfoWidget(QWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
grid = QGridLayout()
|
grid = QGridLayout()
|
||||||
self.setLayout(grid)
|
self.setLayout(grid)
|
||||||
grid.addWidget(QLabel(key.replace("_", " ").title()),0,0,1,4)
|
self.active = QCheckBox()
|
||||||
|
self.active.setChecked(True)
|
||||||
|
grid.addWidget(self.active, 0,0,1,1)
|
||||||
|
grid.addWidget(QLabel(key.replace("_", " ").title()),0,1,1,4)
|
||||||
self.setObjectName(key)
|
self.setObjectName(key)
|
||||||
grid.addWidget(QLabel("Sheet Names (comma seperated):"),1,0)
|
grid.addWidget(QLabel("Sheet Names (comma seperated):"),1,0)
|
||||||
self.sheet = QLineEdit()
|
self.sheet = QLineEdit()
|
||||||
@@ -103,16 +106,19 @@ class InfoWidget(QWidget):
|
|||||||
self.column.setObjectName("column")
|
self.column.setObjectName("column")
|
||||||
grid.addWidget(self.column,2,3)
|
grid.addWidget(self.column,2,3)
|
||||||
|
|
||||||
def parse_form(self) -> dict:
|
def parse_form(self) -> dict|None:
|
||||||
"""
|
"""
|
||||||
Pulls info from the Info form.
|
Pulls info from the Info form.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: sheets, row, column
|
dict: sheets, row, column
|
||||||
"""
|
"""
|
||||||
|
if self.active.isChecked():
|
||||||
return dict(
|
return dict(
|
||||||
sheets = self.sheet.text().split(","),
|
sheets = self.sheet.text().split(","),
|
||||||
row = self.row.value(),
|
row = self.row.value(),
|
||||||
column = self.column.value()
|
column = self.column.value()
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
@@ -6,12 +6,12 @@ from PyQt6.QtWidgets import (
|
|||||||
QWidget, QPushButton, QVBoxLayout,
|
QWidget, QPushButton, QVBoxLayout,
|
||||||
QComboBox, QDateEdit, QLineEdit, QLabel
|
QComboBox, QDateEdit, QLineEdit, QLabel
|
||||||
)
|
)
|
||||||
from PyQt6.QtCore import pyqtSignal
|
from PyQt6.QtCore import pyqtSignal, Qt
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from . import select_open_file, select_save_file
|
from . import select_open_file, select_save_file
|
||||||
import logging, difflib, inspect
|
import logging, difflib, inspect
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tools import Report, Result, check_not_nan, workbook_2_csv, main_form_style, report_result
|
from tools import Report, Result, check_not_nan, main_form_style, report_result
|
||||||
from backend.excel.parser import SheetParser
|
from backend.excel.parser import SheetParser
|
||||||
from backend.validators import PydSubmission, PydReagent
|
from backend.validators import PydSubmission, PydReagent
|
||||||
from backend.db import (
|
from backend.db import (
|
||||||
@@ -26,6 +26,31 @@ from datetime import date
|
|||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
|
class MyQComboBox(QComboBox):
|
||||||
|
def __init__(self, scrollWidget=None, *args, **kwargs):
|
||||||
|
super(MyQComboBox, self).__init__(*args, **kwargs)
|
||||||
|
self.scrollWidget=scrollWidget
|
||||||
|
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||||
|
logger.debug(f"Scrollwidget: {scrollWidget}")
|
||||||
|
|
||||||
|
def wheelEvent(self, *args, **kwargs):
|
||||||
|
if self.hasFocus():
|
||||||
|
return QComboBox.wheelEvent(self, *args, **kwargs)
|
||||||
|
else:
|
||||||
|
return self.scrollWidget.wheelEvent(*args, **kwargs)
|
||||||
|
|
||||||
|
class MyQDateEdit(QDateEdit):
|
||||||
|
def __init__(self, scrollWidget=None, *args, **kwargs):
|
||||||
|
super(MyQDateEdit, self).__init__(*args, **kwargs)
|
||||||
|
self.scrollWidget=scrollWidget
|
||||||
|
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||||
|
|
||||||
|
def wheelEvent(self, *args, **kwargs):
|
||||||
|
if self.hasFocus():
|
||||||
|
return QDateEdit.wheelEvent(self, *args, **kwargs)
|
||||||
|
else:
|
||||||
|
return self.scrollWidget.wheelEvent(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SubmissionFormContainer(QWidget):
|
class SubmissionFormContainer(QWidget):
|
||||||
# A signal carrying a path
|
# A signal carrying a path
|
||||||
@@ -37,6 +62,7 @@ class SubmissionFormContainer(QWidget):
|
|||||||
self.app = self.parent().parent()
|
self.app = self.parent().parent()
|
||||||
# logger.debug(f"App: {self.app}")
|
# logger.debug(f"App: {self.app}")
|
||||||
self.report = Report()
|
self.report = Report()
|
||||||
|
self.setStyleSheet('background-color: light grey;')
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
# NOTE: if import_drag is emitted, importSubmission will fire
|
# NOTE: if import_drag is emitted, importSubmission will fire
|
||||||
self.import_drag.connect(self.importSubmission)
|
self.import_drag.connect(self.importSubmission)
|
||||||
@@ -208,12 +234,11 @@ class SubmissionFormWidget(QWidget):
|
|||||||
match value:
|
match value:
|
||||||
case PydReagent():
|
case PydReagent():
|
||||||
if value.name.lower() != "not applicable":
|
if value.name.lower() != "not applicable":
|
||||||
widget = self.ReagentFormWidget(self, reagent=value, extraction_kit=extraction_kit)
|
widget = self.ReagentFormWidget(parent=self, reagent=value, extraction_kit=extraction_kit)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
widget = None
|
widget = None
|
||||||
case _:
|
case _:
|
||||||
widget = self.InfoItem(self, key=key, value=value, submission_type=submission_type, sub_obj=sub_obj)
|
widget = self.InfoItem(parent=self, key=key, value=value, submission_type=submission_type, sub_obj=sub_obj)
|
||||||
# logger.debug(f"Setting widget enabled to: {not disable}")
|
# logger.debug(f"Setting widget enabled to: {not disable}")
|
||||||
if disable:
|
if disable:
|
||||||
widget.input.setEnabled(False)
|
widget.input.setEnabled(False)
|
||||||
@@ -422,7 +447,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
self.label = self.ParsedQLabel(key=key, value=value)
|
self.label = self.ParsedQLabel(key=key, value=value)
|
||||||
self.input: QWidget = self.set_widget(parent=self, key=key, value=value, submission_type=submission_type,
|
self.input: QWidget = self.set_widget(parent=parent, key=key, value=value, submission_type=submission_type,
|
||||||
sub_obj=sub_obj)
|
sub_obj=sub_obj)
|
||||||
self.setObjectName(key)
|
self.setObjectName(key)
|
||||||
try:
|
try:
|
||||||
@@ -481,10 +506,12 @@ class SubmissionFormWidget(QWidget):
|
|||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
obj = parent.parent().parent()
|
obj = parent.parent().parent()
|
||||||
|
logger.debug(f"Object: {obj}")
|
||||||
|
logger.debug(f"Parent: {parent.parent()}")
|
||||||
# logger.debug(f"Creating widget for: {key}")
|
# logger.debug(f"Creating widget for: {key}")
|
||||||
match key:
|
match key:
|
||||||
case 'submitting_lab':
|
case 'submitting_lab':
|
||||||
add_widget = QComboBox()
|
add_widget = MyQComboBox(scrollWidget=parent)
|
||||||
# lookup organizations suitable for submitting_lab (ctx: self.InfoItem.SubmissionFormWidget.SubmissionFormContainer.AddSubForm )
|
# lookup organizations suitable for submitting_lab (ctx: self.InfoItem.SubmissionFormWidget.SubmissionFormContainer.AddSubForm )
|
||||||
labs = [item.name for item in Organization.query()]
|
labs = [item.name for item in Organization.query()]
|
||||||
# try to set closest match to top of list
|
# try to set closest match to top of list
|
||||||
@@ -502,7 +529,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
status="warning")
|
status="warning")
|
||||||
msg.exec()
|
msg.exec()
|
||||||
# NOTE: create combobox to hold looked up kits
|
# NOTE: create combobox to hold looked up kits
|
||||||
add_widget = QComboBox()
|
add_widget = MyQComboBox(scrollWidget=parent)
|
||||||
# NOTE: lookup existing kits by 'submission_type' decided on by sheetparser
|
# NOTE: lookup existing kits by 'submission_type' decided on by sheetparser
|
||||||
# logger.debug(f"Looking up kits used for {submission_type}")
|
# logger.debug(f"Looking up kits used for {submission_type}")
|
||||||
uses = [item.name for item in KitType.query(used_for=submission_type)]
|
uses = [item.name for item in KitType.query(used_for=submission_type)]
|
||||||
@@ -518,7 +545,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
add_widget.addItems(uses)
|
add_widget.addItems(uses)
|
||||||
add_widget.setToolTip("Select extraction kit.")
|
add_widget.setToolTip("Select extraction kit.")
|
||||||
case 'submission_category':
|
case 'submission_category':
|
||||||
add_widget = QComboBox()
|
add_widget = MyQComboBox(scrollWidget=parent)
|
||||||
cats = ['Diagnostic', "Surveillance", "Research"]
|
cats = ['Diagnostic', "Surveillance", "Research"]
|
||||||
cats += [item.name for item in SubmissionType.query()]
|
cats += [item.name for item in SubmissionType.query()]
|
||||||
try:
|
try:
|
||||||
@@ -529,7 +556,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
add_widget.setToolTip("Enter submission category or select from list.")
|
add_widget.setToolTip("Enter submission category or select from list.")
|
||||||
case _:
|
case _:
|
||||||
if key in sub_obj.timestamps():
|
if key in sub_obj.timestamps():
|
||||||
add_widget = QDateEdit(calendarPopup=True)
|
add_widget = MyQDateEdit(calendarPopup=True, scrollWidget=parent)
|
||||||
# NOTE: sets submitted date based on date found in excel sheet
|
# NOTE: sets submitted date based on date found in excel sheet
|
||||||
try:
|
try:
|
||||||
add_widget.setDate(value)
|
add_widget.setDate(value)
|
||||||
@@ -601,7 +628,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
self.label = self.ReagentParsedLabel(reagent=reagent)
|
self.label = self.ReagentParsedLabel(reagent=reagent)
|
||||||
layout.addWidget(self.label)
|
layout.addWidget(self.label)
|
||||||
self.lot = self.ReagentLot(reagent=reagent, extraction_kit=extraction_kit)
|
self.lot = self.ReagentLot(scrollWidget=parent, reagent=reagent, extraction_kit=extraction_kit)
|
||||||
# self.lot.setStyleSheet(main_form_style)
|
# self.lot.setStyleSheet(main_form_style)
|
||||||
layout.addWidget(self.lot)
|
layout.addWidget(self.lot)
|
||||||
# NOTE: Remove spacing between reagents
|
# NOTE: Remove spacing between reagents
|
||||||
@@ -677,10 +704,10 @@ class SubmissionFormWidget(QWidget):
|
|||||||
"""
|
"""
|
||||||
self.setText(f"UPDATED {reagent_role}")
|
self.setText(f"UPDATED {reagent_role}")
|
||||||
|
|
||||||
class ReagentLot(QComboBox):
|
class ReagentLot(MyQComboBox):
|
||||||
|
|
||||||
def __init__(self, reagent, extraction_kit: str) -> None:
|
def __init__(self, scrollWidget, reagent, extraction_kit: str) -> None:
|
||||||
super().__init__()
|
super().__init__(scrollWidget=scrollWidget)
|
||||||
self.setEditable(True)
|
self.setEditable(True)
|
||||||
# logger.debug(f"Attempting lookup of reagents by type: {reagent.type}")
|
# logger.debug(f"Attempting lookup of reagents by type: {reagent.type}")
|
||||||
# NOTE: below was lookup_reagent_by_type_name_and_kit_name, but I couldn't get it to work.
|
# NOTE: below was lookup_reagent_by_type_name_and_kit_name, but I couldn't get it to work.
|
||||||
@@ -731,3 +758,6 @@ class SubmissionFormWidget(QWidget):
|
|||||||
self.addItems(relevant_reagents)
|
self.addItems(relevant_reagents)
|
||||||
self.setToolTip(f"Enter lot number for the reagent used for {reagent.role}")
|
self.setToolTip(f"Enter lot number for the reagent used for {reagent.role}")
|
||||||
# self.setStyleSheet(main_form_style)
|
# self.setStyleSheet(main_form_style)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
8
src/submissions/templates/experiment_template.json
Normal file
8
src/submissions/templates/experiment_template.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"submission_type" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"kit_type": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user