New table view.

This commit is contained in:
lwark
2025-05-06 13:21:03 -05:00
parent 5508f68bc8
commit 20952f2edd
10 changed files with 382 additions and 17 deletions

View File

@@ -22,7 +22,7 @@ from .date_type_picker import DateTypePicker
from .functions import select_save_file
from .pop_ups import HTMLPop
from .misc import Pagifier
from .submission_table import SubmissionsSheet
from .submission_table import SubmissionsSheet, SubmissionsTree, ClientRunModel
from .submission_widget import SubmissionFormContainer
from .controls_chart import ControlsViewer
from .summary import Summary
@@ -253,7 +253,8 @@ class AddSubForm(QWidget):
self.sheetwidget = QWidget(self)
self.sheetlayout = QVBoxLayout(self)
self.sheetwidget.setLayout(self.sheetlayout)
self.sub_wid = SubmissionsSheet(parent=parent)
# self.sub_wid = SubmissionsSheet(parent=parent)
self.sub_wid = SubmissionsTree(parent=parent, model=ClientRunModel(self))
self.pager = Pagifier(page_max=self.sub_wid.total_count / page_size)
self.sheetlayout.addWidget(self.sub_wid)
self.sheetlayout.addWidget(self.pager)

View File

@@ -34,7 +34,11 @@ class SampleChecker(QDialog):
template_path = Path(template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
css = f.read()
html = template.render(samples=self.formatted_list, css=css)
try:
samples = self.formatted_list
except AttributeError:
samples = []
html = template.render(samples=samples, css=css)
self.webview.setHtml(html)
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
self.buttonBox = QDialogButtonBox(QBtn)

View File

@@ -2,11 +2,13 @@
Contains widgets specific to the submission summary and submission details.
"""
import logging
import sys
from pprint import pformat
from PyQt6.QtWidgets import QTableView, QMenu
from PyQt6.QtCore import Qt, QAbstractTableModel, QSortFilterProxyModel
from PyQt6.QtGui import QAction, QCursor
from backend.db.models import BasicSubmission
from PyQt6.QtWidgets import QTableView, QMenu, QTreeView, QStyledItemDelegate, QStyle, QStyleOptionViewItem, \
QHeaderView, QAbstractItemView
from PyQt6.QtCore import Qt, QAbstractTableModel, QSortFilterProxyModel, pyqtSlot, QModelIndex
from PyQt6.QtGui import QAction, QCursor, QStandardItemModel, QStandardItem, QIcon, QColor
from backend.db.models import BasicSubmission, ClientSubmission
from tools import Report, Result, report_result
from .functions import select_open_file
@@ -84,6 +86,7 @@ class SubmissionsSheet(QTableView):
"""
sets data in model
"""
# self.data = ClientSubmission.submissions_to_df(page=page, page_size=page_size)
self.data = BasicSubmission.submissions_to_df(page=page, page_size=page_size)
try:
self.data['Id'] = self.data['Id'].apply(str)
@@ -222,3 +225,106 @@ class SubmissionsSheet(QTableView):
sub.save()
report.add_result(Result(msg=f"We added {count} logs to the database.", status='Information'))
return report
class RunDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super(RunDelegate, self).__init__(parent)
self._plus_icon = QIcon("plus.png")
self._minus_icon = QIcon("minus.png")
def initStyleOption(self, option, index):
super(RunDelegate, self).initStyleOption(option, index)
if not index.parent().isValid():
is_open = bool(option.state & QStyle.StateFlag.State_Open)
option.features |= QStyleOptionViewItem.ViewItemFeature.HasDecoration
option.icon = self._minus_icon if is_open else self._plus_icon
class SubmissionsTree(QTreeView):
"""
https://stackoverflow.com/questions/54385437/how-can-i-make-a-table-that-can-collapse-its-rows-into-categories-in-qt
"""
def __init__(self, model, parent=None):
super(SubmissionsTree, self).__init__(parent)
self.total_count = 1
self.setIndentation(0)
self.setExpandsOnDoubleClick(False)
self.clicked.connect(self.on_clicked)
delegate = RunDelegate(self)
self.setItemDelegateForColumn(0, delegate)
self.model = model
self.setModel(self.model)
# self.header().setSectionResizeMode(0, QHeaderView.sectionResizeMode(self,0).ResizeToContents)
self.setSelectionBehavior(QAbstractItemView.selectionBehavior(self).SelectRows)
# self.setStyleSheet("background-color: #0D1225;")
self.set_data()
@pyqtSlot(QModelIndex)
def on_clicked(self, index):
if not index.parent().isValid() and index.column() == 0:
self.setExpanded(index, not self.isExpanded(index))
def set_data(self, page: int = 1, page_size: int = 250) -> None:
"""
sets data in model
"""
# self.data = ClientSubmission.submissions_to_df(page=page, page_size=page_size)
self.data = [item.to_dict(full_data=True) for item in ClientSubmission.query(chronologic=True, page=page, page_size=page_size)]
logger.debug(pformat(self.data))
# sys.exit()
for submission in self.data:
group_item = self.model.add_group(submission['submitter_plate_number'])
for run in submission['runs']:
self.model.append_element_to_group(group_item=group_item, texts=run['plate_number'])
def link_extractions(self):
pass
def link_pcr(self):
pass
class ClientRunModel(QStandardItemModel):
def __init__(self, parent=None):
super(ClientRunModel, self).__init__(parent)
self.setColumnCount(8)
self.setHorizontalHeaderLabels(["id", "Name", "Library", "Release Date", "Genre(s)", "Last Played", "Time Played", ""])
for i in range(self.columnCount()):
it = self.horizontalHeaderItem(i)
# it.setForeground(QColor("#F2F2F2"))
def add_group(self, group_name):
item_root = QStandardItem()
item_root.setEditable(False)
item = QStandardItem(group_name)
item.setEditable(False)
ii = self.invisibleRootItem()
i = ii.rowCount()
for j, it in enumerate((item_root, item)):
ii.setChild(i, j, it)
ii.setEditable(False)
for j in range(self.columnCount()):
it = ii.child(i, j)
if it is None:
it = QStandardItem()
ii.setChild(i, j, it)
# it.setBackground(QColor("#002842"))
# it.setForeground(QColor("#F2F2F2"))
return item_root
def append_element_to_group(self, group_item, texts):
j = group_item.rowCount()
item_icon = QStandardItem()
item_icon.setEditable(False)
item_icon.setIcon(QIcon("game.png"))
# item_icon.setBackground(QColor("#0D1225"))
group_item.setChild(j, 0, item_icon)
for i, text in enumerate(texts):
item = QStandardItem(text)
item.setEditable(False)
# item.setBackground(QColor("#0D1225"))
# item.setForeground(QColor("#F2F2F2"))
group_item.setChild(j, i+1, item)

View File

@@ -10,7 +10,7 @@ from .functions import select_open_file, select_save_file
import logging
from pathlib import Path
from tools import Report, Result, check_not_nan, main_form_style, report_result, get_application_from_parent
from backend.excel.parser import SheetParser
from backend.excel.parsers import SheetParser, InfoParserV2
from backend.validators import PydSubmission, PydReagent
from backend.db import (
Organization, SubmissionType, Reagent,
@@ -121,13 +121,14 @@ class SubmissionFormContainer(QWidget):
return report
# NOTE: create sheetparser using excel sheet and context from gui
try:
self.prsr = SheetParser(filepath=fname)
# self.prsr = SheetParser(filepath=fname)
self.parser = InfoParserV2(filepath=fname)
except PermissionError:
logger.error(f"Couldn't get permission to access file: {fname}")
return
except AttributeError:
self.prsr = SheetParser(filepath=fname)
self.pyd = self.prsr.to_pydantic()
self.parser = InfoParserV2(filepath=fname)
self.pyd = self.parser.to_pydantic()
# logger.debug(f"Samples: {pformat(self.pyd.samples)}")
checker = SampleChecker(self, "Sample Checker", self.pyd)
if checker.exec():
@@ -177,11 +178,13 @@ class SubmissionFormWidget(QWidget):
self.missing_info = []
self.submission_type = SubmissionType.query(name=self.pyd.submission_type['value'])
basic_submission_class = self.submission_type.submission_class
logger.debug(f"Basic submission class: {basic_submission_class}")
defaults = basic_submission_class.get_default_info("form_recover", "form_ignore", submission_type=self.pyd.submission_type['value'])
self.recover = defaults['form_recover']
self.ignore = defaults['form_ignore']
self.layout = QVBoxLayout()
for k in list(self.pyd.model_fields.keys()) + list(self.pyd.model_extra.keys()):
logger.debug(f"Pydantic field: {k}")
if k in self.ignore:
logger.warning(f"{k} in form_ignore {self.ignore}, not creating widget")
continue
@@ -197,6 +200,7 @@ class SubmissionFormWidget(QWidget):
value = self.pyd.model_extra[k]
except KeyError:
value = dict(value=None, missing=True)
logger.debug(f"Pydantic value: {value}")
add_widget = self.create_widget(key=k, value=value, submission_type=self.submission_type,
sub_obj=basic_submission_class, disable=check)
if add_widget is not None:
@@ -208,7 +212,8 @@ class SubmissionFormWidget(QWidget):
self.layout.addWidget(self.disabler)
self.disabler.checkbox.checkStateChanged.connect(self.disable_reagents)
self.setStyleSheet(main_form_style)
self.scrape_reagents(self.extraction_kit)
# self.scrape_reagents(self.extraction_kit)
self.setLayout(self.layout)
def disable_reagents(self):
"""
@@ -774,3 +779,16 @@ class SubmissionFormWidget(QWidget):
layout.addWidget(self.label)
layout.addWidget(self.checkbox)
self.setLayout(layout)
class ClientSubmissionFormWidget(SubmissionFormWidget):
def __init__(self, parent: QWidget, submission: PydSubmission, disable: list | None = None) -> None:
super().__init__(parent, submission=submission, disable=disable)
save_btn = QPushButton("Save")
start_run_btn = QPushButton("Save && Start Run")
self.layout.addWidget(save_btn)
self.layout.addWidget(start_run_btn)