Update of Reagent usage ui for addition of new reagents.

This commit is contained in:
lwark
2025-07-02 13:42:40 -05:00
parent fd63608744
commit c4c330b90c
8 changed files with 154 additions and 83 deletions

View File

@@ -603,7 +603,7 @@ class BaseClass(Base):
pyd = getattr(pydant, pyd_model_name) pyd = getattr(pydant, pyd_model_name)
except AttributeError: except AttributeError:
raise AttributeError(f"Could not get pydantic class {pyd_model_name}") raise AttributeError(f"Could not get pydantic class {pyd_model_name}")
return pyd(**self.details_dict()) return pyd(**self.details_dict(**kwargs))
def show_details(self, obj): def show_details(self, obj):
logger.debug("Show Details") logger.debug("Show Details")

View File

@@ -5,13 +5,11 @@ from __future__ import annotations
import zipfile, logging, re import zipfile, logging, re
from operator import itemgetter from operator import itemgetter
from pprint import pformat from pprint import pformat
import numpy as np import numpy as np
from sqlalchemy import Column, String, TIMESTAMP, JSON, INTEGER, ForeignKey, Interval, Table, FLOAT, BLOB from sqlalchemy import Column, String, TIMESTAMP, JSON, INTEGER, ForeignKey, Interval, Table, FLOAT, BLOB
from sqlalchemy.orm import relationship, validates, Query from sqlalchemy.orm import relationship, validates, Query
from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.associationproxy import association_proxy
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from tools import check_authorization, setup_lookup, Report, Result, check_regex_match, timezone, \ from tools import check_authorization, setup_lookup, Report, Result, check_regex_match, timezone, \
jinja_template_loading, flatten_list jinja_template_loading, flatten_list
from typing import List, Literal, Generator, Any, Tuple, TYPE_CHECKING from typing import List, Literal, Generator, Any, Tuple, TYPE_CHECKING
@@ -562,7 +560,8 @@ class ReagentRole(BaseClass):
def get_reagents(self, kittype: str | KitType | None = None): def get_reagents(self, kittype: str | KitType | None = None):
if not kittype: if not kittype:
return [f"{reagent.name} - {reagent.lot}" for reagent in self.reagent] # return [f"{reagent.name} - {reagent.lot} - {reagent.expiry}" for reagent in self.reagent]
return [reagent.to_pydantic() for reagent in self.reagent]
if isinstance(kittype, str): if isinstance(kittype, str):
kittype = KitType.query(name=kittype) kittype = KitType.query(name=kittype)
assoc = next((item for item in self.reagentrolekittypeassociation if item.kittype == kittype), None) assoc = next((item for item in self.reagentrolekittypeassociation if item.kittype == kittype), None)
@@ -571,7 +570,8 @@ class ReagentRole(BaseClass):
last_used = Reagent.query(name=assoc.last_used) last_used = Reagent.query(name=assoc.last_used)
if last_used: if last_used:
reagents.insert(0, reagents.pop(reagents.index(last_used))) reagents.insert(0, reagents.pop(reagents.index(last_used)))
return [f"{reagent.name} - {reagent.lot}" for reagent in reagents] # return [f"{reagent.name} - {reagent.lot} - {reagent.expiry}" for reagent in reagents]
return [reagent.to_pydantic(reagentrole=self.name) for reagent in reagents]
class Reagent(BaseClass, LogMixin): class Reagent(BaseClass, LogMixin):
@@ -680,24 +680,24 @@ class Reagent(BaseClass, LogMixin):
report.add_result(Result(msg=f"Updating last used {rt} was not performed.", status="Information")) report.add_result(Result(msg=f"Updating last used {rt} was not performed.", status="Information"))
return report return report
@classmethod # @classmethod
def query_or_create(cls, **kwargs) -> Reagent: # def query_or_create(cls, **kwargs) -> Reagent:
from backend.validators.pydant import PydReagent # from backend.validators.pydant import PydReagent
new = False # new = False
disallowed = ['expiry'] # disallowed = ['expiry']
sanitized_kwargs = {k: v for k, v in kwargs.items() if k not in disallowed} # sanitized_kwargs = {k: v for k, v in kwargs.items() if k not in disallowed}
instance = cls.query(**sanitized_kwargs) # instance = cls.query(**sanitized_kwargs)
if not instance or isinstance(instance, list): # if not instance or isinstance(instance, list):
if "reagentrole" not in kwargs: # if "reagentrole" not in kwargs:
try: # try:
kwargs['reagentrole'] = kwargs['name'] # kwargs['reagentrole'] = kwargs['name']
except KeyError: # except KeyError:
pass # pass
instance = PydReagent(**kwargs) # instance = PydReagent(**kwargs)
new = True # new = True
instance = instance.to_sql() # instance = instance.to_sql()
logger.info(f"Instance from query or create: {instance}") # logger.info(f"Instance from query or create: {instance}")
return instance, new # return instance, new
@classmethod @classmethod
@setup_lookup @setup_lookup
@@ -800,6 +800,12 @@ class Reagent(BaseClass, LogMixin):
expiry="Use exact date on reagent.\nEOL will be calculated from kittype automatically" expiry="Use exact date on reagent.\nEOL will be calculated from kittype automatically"
) )
def details_dict(self, reagentrole:str|None=None, **kwargs):
output = super().details_dict()
if reagentrole:
output['reagentrole'] = reagentrole
return output
class Discount(BaseClass): class Discount(BaseClass):
""" """
@@ -1278,7 +1284,7 @@ class ProcedureType(BaseClass):
if self.plate_rows == 0 or self.plate_columns == 0: if self.plate_rows == 0 or self.plate_columns == 0:
return "<br/>" return "<br/>"
sample_dicts = self.pad_sample_dicts(sample_dicts=sample_dicts) sample_dicts = self.pad_sample_dicts(sample_dicts=sample_dicts)
logger.debug(f"Sample dicts: {pformat(sample_dicts)}") # logger.debug(f"Sample dicts: {pformat(sample_dicts)}")
vw = round((-0.07 * len(sample_dicts)) + 12.2, 1) vw = round((-0.07 * len(sample_dicts)) + 12.2, 1)
# NOTE: An overly complicated list comprehension create a list of sample locations # NOTE: An overly complicated list comprehension create a list of sample locations
# NOTE: next will return a blank cell if no value found for row/column # NOTE: next will return a blank cell if no value found for row/column
@@ -1291,14 +1297,14 @@ class ProcedureType(BaseClass):
def pad_sample_dicts(self, sample_dicts: List["PydSample"]): def pad_sample_dicts(self, sample_dicts: List["PydSample"]):
from backend.validators.pydant import PydSample from backend.validators.pydant import PydSample
output = [] output = []
logger.debug(f"Rows: {self.plate_rows}") # logger.debug(f"Rows: {self.plate_rows}")
logger.debug(f"Columns: {self.plate_columns}") # logger.debug(f"Columns: {self.plate_columns}")
for row, column in self.ranked_plate.values(): for row, column in self.ranked_plate.values():
sample = next((sample for sample in sample_dicts if sample.row == row and sample.column == column), sample = next((sample for sample in sample_dicts if sample.row == row and sample.column == column),
PydSample(**dict(sample_id="", row=row, column=column, enabled=False))) PydSample(**dict(sample_id="", row=row, column=column, enabled=False)))
sample.background_color = "#6ffe1d" if sample.enabled else "#ffffff" sample.background_color = "#6ffe1d" if sample.enabled else "#ffffff"
output.append(sample) output.append(sample)
logger.debug(f"Appending {sample} at row {row}, column {column}") # logger.debug(f"Appending {sample} at row {row}, column {column}")
return output return output
@@ -1453,6 +1459,8 @@ class Procedure(BaseClass):
dlg = ProcedureCreation(parent=obj, procedure=self.to_pydantic(), edit=True) dlg = ProcedureCreation(parent=obj, procedure=self.to_pydantic(), edit=True)
if dlg.exec(): if dlg.exec():
logger.debug("Edited") logger.debug("Edited")
sql, _ = dlg.return_sql()
sql.save()
def add_comment(self, obj): def add_comment(self, obj):
logger.debug("Add Comment!") logger.debug("Add Comment!")

View File

@@ -183,7 +183,7 @@ class PydReagent(PydBaseClass):
case _: case _:
return convert_nans_to_nones(str(value)) return convert_nans_to_nones(str(value))
if value is None: if value is None:
value = date.today() value = datetime.combine(date.today(), datetime.max.time())
return value return value
@field_validator("expiry") @field_validator("expiry")
@@ -201,6 +201,11 @@ class PydReagent(PydBaseClass):
else: else:
return values.data['reagentrole'].strip() return values.data['reagentrole'].strip()
# @field_validator("reagentrole", mode="before")
# @classmethod
# def rescue_reagentrole(cls, value):
# if
def improved_dict(self) -> dict: def improved_dict(self) -> dict:
""" """
Constructs a dictionary consisting of model.fields and model.extras Constructs a dictionary consisting of model.fields and model.extras
@@ -226,23 +231,26 @@ class PydReagent(PydBaseClass):
report = Report() report = Report()
if self.model_extra is not None: if self.model_extra is not None:
self.__dict__.update(self.model_extra) self.__dict__.update(self.model_extra)
reagent = Reagent.query(lot=self.lot, name=self.name) reagent, new = Reagent.query_or_create(lot=self.lot, name=self.name)
# logger.debug(f"Reagent: {reagent}") # logger.debug(f"Reagent: {reagent}")
if reagent is None: # if reagent is None:
reagent = Reagent() # reagent = Reagent()
for key, value in self.__dict__.items(): # for key, value in self.__dict__.items():
if isinstance(value, dict): # if isinstance(value, dict):
value = value['value'] # if key == "misc_info":
# NOTE: reagent method sets fields based on keys in dictionary # value = value
reagent.set_attribute(key, value) # else:
if procedure is not None and reagent not in procedure.reagents: # value = value['value']
assoc = ProcedureReagentAssociation(reagent=reagent, procedure=procedure) # # NOTE: reagent method sets fields based on keys in dictionary
assoc.comments = self.comment # reagent.set_attribute(key, value)
else: # if procedure is not None and reagent not in procedure.reagents:
assoc = None # assoc = ProcedureReagentAssociation(reagent=reagent, procedure=procedure)
else: # assoc.comments = self.comment
if submission is not None and reagent not in submission.reagents: # else:
submission.update_reagentassoc(reagent=reagent, role=self.role) # assoc = None
# else:
# if submission is not None and reagent not in submission.reagents:
# submission.update_reagentassoc(reagent=reagent, role=self.role)
return reagent, report return reagent, report
@@ -1486,8 +1494,10 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
if isinstance(kittype, str): if isinstance(kittype, str):
kittype_obj = KitType.query(name=kittype) kittype_obj = KitType.query(name=kittype)
try: try:
self.reagentrole = {item.name: item.get_reagents(kittype=kittype_obj) + ["New"] for item in self.reagentrole = {
kittype_obj.get_reagents(proceduretype=self.proceduretype)} item.name: item.get_reagents(kittype=kittype_obj) + [PydReagent(name="--New--", lot="", reagentrole="")]
for item in
kittype_obj.get_reagents(proceduretype=self.proceduretype)}
except AttributeError: except AttributeError:
self.reagentrole = {} self.reagentrole = {}
@@ -1511,19 +1521,19 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
logger.debug(f"Incoming sample_list:\n{pformat(sample_list)}") logger.debug(f"Incoming sample_list:\n{pformat(sample_list)}")
for sample_dict in sample_list: for sample_dict in sample_list:
if sample_dict['sample_id'].startswith("blank_"): if sample_dict['sample_id'].startswith("blank_"):
continue sample_dict['sample_id'] = ""
row, column = self.proceduretype.ranked_plate[sample_dict['index']] row, column = self.proceduretype.ranked_plate[sample_dict['index']]
logger.debug(f"Row: {row}, Column: {column}") logger.debug(f"Row: {row}, Column: {column}")
try: try:
sample = next( sample = next(
(item for item in self.samples if item.sample_id.upper() == sample_dict['sample_id'].upper())) (item for item in self.sample if item.sample_id.upper() == sample_dict['sample_id'].upper()))
except StopIteration: except StopIteration:
# NOTE: Code to check for added controls. # NOTE: Code to check for added controls.
logger.debug( logger.debug(
f"Sample not found by name: {sample_dict['sample_id']}, checking row {row} column {column}") f"Sample not found by name: {sample_dict['sample_id']}, checking row {row} column {column}")
try: try:
sample = next( sample = next(
(item for item in self.samples if item.row == row and item.column == column)) (item for item in self.sample if item.row == row and item.column == column))
except StopIteration: except StopIteration:
logger.error(f"Couldn't find sample: {pformat(sample_dict)}") logger.error(f"Couldn't find sample: {pformat(sample_dict)}")
continue continue
@@ -1532,7 +1542,23 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
sample.well_id = sample_dict['sample_id'] sample.well_id = sample_dict['sample_id']
sample.row = row sample.row = row
sample.column = column sample.column = column
logger.debug(f"Updated samples:\n{pformat(self.samples)}") # logger.debug(f"Updated samples:\n{pformat(self.sample)}")
def update_reagents(self, reagentrole: str, name: str, lot: str, expiry: str):
removable = next((item for item in self.reagent if item.reagentrole == reagentrole), None)
if removable:
idx = self.reagent.index(removable)
self.reagent.remove(removable)
else:
idx = 0
insertable = PydReagent(reagentrole=reagentrole, name=name, lot=lot, expiry=expiry)
self.reagent.insert(idx, insertable)
logger.debug(self.reagent)
@classmethod
def update_new_reagents(cls, reagent: PydReagent):
reg = reagent.to_sql()
reg.save()
def to_sql(self): def to_sql(self):
from backend.db.models import RunSampleAssociation, ProcedureSampleAssociation from backend.db.models import RunSampleAssociation, ProcedureSampleAssociation
@@ -1540,12 +1566,24 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
# for result in self.results: # for result in self.results:
# result, _ = result.to_sql() # result, _ = result.to_sql()
sql = super().to_sql() sql = super().to_sql()
logger.debug(f"Initial PYD: {pformat(self.__dict__)}") # logger.debug(f"Initial PYD: {pformat(self.__dict__)}")
# sql.results = [result.to_sql() for result in self.results] # sql.results = [result.to_sql() for result in self.results]
if self.run: if self.run:
sql.run = self.run sql.run = self.run
if self.proceduretype: if self.proceduretype:
sql.proceduretype = self.proceduretype sql.proceduretype = self.proceduretype
# Note: convert any new reagents to sql and save
for reagentrole, reagents in self.reagentrole.items():
for reagent in reagents:
if not reagent.lot or reagent.name == "--New--":
continue
self.update_new_reagents(reagent)
# NOTE: reset reagent associations.
sql.procedurereagentassociation = []
for reagent in self.reagent:
reagent = reagent.to_sql()
if reagent not in sql.reagent:
reagent_assoc = ProcedureReagentAssociation(reagent=reagent, procedure=sql)
try: try:
start_index = max([item.id for item in ProcedureSampleAssociation.query()]) + 1 start_index = max([item.id for item in ProcedureSampleAssociation.query()]) + 1
except ValueError: except ValueError:
@@ -1571,13 +1609,15 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
kittype = KitType.query(name=self.kittype['value'], limit=1) kittype = KitType.query(name=self.kittype['value'], limit=1)
if kittype: if kittype:
sql.kittype = kittype sql.kittype = kittype
logger.debug(self.reagent)
for equipment in self.equipment: for equipment in self.equipment:
equip = Equipment.query(name=equipment.name) equip = Equipment.query(name=equipment.name)
if equip not in sql.equipment: if equip not in sql.equipment:
equip_assoc = ProcedureEquipmentAssociation(equipment=equip, procedure=sql, equipmentrole=equip.equipmentrole[0]) equip_assoc = ProcedureEquipmentAssociation(equipment=equip, procedure=sql,
equipmentrole=equip.equipmentrole[0])
process = equipment.process.to_sql() process = equipment.process.to_sql()
equip_assoc.process = process equip_assoc.process = process
logger.debug(f"Output sql: {[pformat(item.__dict__) for item in sql.procedureequipmentassociation]}") # logger.debug(f"Output sql: {[pformat(item.__dict__) for item in sql.procedureequipmentassociation]}")
return sql, None return sql, None

View File

@@ -3,6 +3,7 @@
""" """
from __future__ import annotations from __future__ import annotations
import datetime
import os import os
import sys, logging import sys, logging
from pathlib import Path from pathlib import Path
@@ -122,6 +123,24 @@ class ProcedureCreation(QDialog):
def log(self, logtext: str): def log(self, logtext: str):
logger.debug(logtext) logger.debug(logtext)
@pyqtSlot(str, str, str, str)
def add_new_reagent(self, reagentrole: str, name: str, lot: str, expiry: str):
from backend.validators.pydant import PydReagent
expiry = datetime.datetime.strptime(expiry, "%Y-%m-%d")
pyd = PydReagent(reagentrole=reagentrole, name=name, lot=lot, expiry=expiry)
logger.debug(pyd)
self.procedure.reagentrole[reagentrole].insert(0, pyd)
logger.debug(pformat(self.procedure.__dict__))
self.set_html()
@pyqtSlot(str, str)
def update_reagent(self, reagentrole:str, name_lot_expiry:str):
try:
name, lot, expiry = name_lot_expiry.split(" - ")
except ValueError:
return
self.procedure.update_reagents(reagentrole=reagentrole, name=name, lot=lot, expiry=expiry)
def return_sql(self): def return_sql(self):
return self.procedure.to_sql() return self.procedure.to_sql()

View File

@@ -296,7 +296,7 @@ class SubmissionsTree(QTreeView):
self.setAlternatingRowColors(True) self.setAlternatingRowColors(True)
self.setIndentation(20) self.setIndentation(20)
self.setItemsExpandable(True) self.setItemsExpandable(True)
self.expanded.connect(self.expand_item) # self.expanded.connect(self.expand_item)
for ii in range(2): for ii in range(2):
self.resizeColumnToContents(ii) self.resizeColumnToContents(ii)

View File

@@ -32,24 +32,24 @@ gridContainer.addEventListener("drop", (e) => {
targetItem !== draggedItem //&& targetItem !== draggedItem //&&
//targetItem.classList.contains("well") //targetItem.classList.contains("well")
) { ) {
backend.log(targetItem.id); // backend.log(targetItem.id);
const draggedIndex = [...gridContainer.children].indexOf(draggedItem); const draggedIndex = [...gridContainer.children].indexOf(draggedItem);
const targetIndex = [...gridContainer.children].indexOf(targetItem); const targetIndex = [...gridContainer.children].indexOf(targetItem);
if (draggedIndex < targetIndex) { if (draggedIndex < targetIndex) {
backend.log(draggedIndex.toString() + " " + targetIndex.toString() + " Lesser"); // backend.log(draggedIndex.toString() + " " + targetIndex.toString() + " Lesser");
gridContainer.insertBefore(draggedItem, targetItem.nextSibling); gridContainer.insertBefore(draggedItem, targetItem.nextSibling);
} else { } else {
backend.log(draggedIndex.toString() + " " + targetIndex.toString() + " Greater"); // backend.log(draggedIndex.toString() + " " + targetIndex.toString() + " Greater");
gridContainer.insertBefore(draggedItem, targetItem); gridContainer.insertBefore(draggedItem, targetItem);
} }
// output = []; output = [];
// fullGrid = [...gridContainer.children]; fullGrid = [...gridContainer.children];
// fullGrid.forEach(function(item, index) { fullGrid.forEach(function(item, index) {
// output.push({sample_id: item.id, index: index + 1}) output.push({sample_id: item.id, index: index + 1})
// }); });
// backend.rearrange_plate(output); backend.rearrange_plate(output);
rearrange_plate(); // rearrange_plate();
} }
}); });

View File

@@ -21,45 +21,39 @@ for(let i = 0; i < formtexts.length; i++) {
}) })
}; };
var changed_it = new Event('change');
var reagentRoles = document.getElementsByClassName("reagentrole"); var reagentRoles = document.getElementsByClassName("reagentrole");
for(let i = 0; i < reagentRoles.length; i++) { for(let i = 0; i < reagentRoles.length; i++) {
reagentRoles[i].addEventListener("change", function() { reagentRoles[i].addEventListener("change", function() {
if (reagentRoles[i].value === "New") { if (reagentRoles[i].value.includes("--New--")) {
var br = document.createElement("br"); var br = document.createElement("br");
var new_reg = document.getElementById("new_" + reagentRoles[i].id); var new_reg = document.getElementById("new_" + reagentRoles[i].id);
console.log(new_reg.id);
var new_form = document.createElement("form"); var new_form = document.createElement("form");
new_form.setAttribute("class", "new_reagent_form")
new_form.setAttribute("id", reagentRoles[i].id + "_addition")
var rr_name = document.createElement("input"); var rr_name = document.createElement("input");
rr_name.setAttribute("type", "text"); rr_name.setAttribute("type", "text");
rr_name.setAttribute("id", "new_" + reagentRoles[i].id + "_name"); rr_name.setAttribute("id", "new_" + reagentRoles[i].id + "_name");
var rr_name_label = document.createElement("label"); var rr_name_label = document.createElement("label");
rr_name_label.setAttribute("for", "new_" + reagentRoles[i].id + "_name"); rr_name_label.setAttribute("for", "new_" + reagentRoles[i].id + "_name");
rr_name_label.innerHTML = "Name:"; rr_name_label.innerHTML = "Name:";
var rr_lot = document.createElement("input"); var rr_lot = document.createElement("input");
rr_lot.setAttribute("type", "text"); rr_lot.setAttribute("type", "text");
rr_lot.setAttribute("id", "new_" + reagentRoles[i].id + "_lot"); rr_lot.setAttribute("id", "new_" + reagentRoles[i].id + "_lot");
var rr_lot_label = document.createElement("label"); var rr_lot_label = document.createElement("label");
rr_lot_label.setAttribute("for", "new_" + reagentRoles[i].id + "_lot"); rr_lot_label.setAttribute("for", "new_" + reagentRoles[i].id + "_lot");
rr_lot_label.innerHTML = "Lot:"; rr_lot_label.innerHTML = "Lot:";
var rr_expiry = document.createElement("input"); var rr_expiry = document.createElement("input");
rr_expiry.setAttribute("type", "date"); rr_expiry.setAttribute("type", "date");
rr_expiry.setAttribute("id", "new_" + reagentRoles[i].id + "_expiry"); rr_expiry.setAttribute("id", "new_" + reagentRoles[i].id + "_expiry");
var rr_expiry_label = document.createElement("label"); var rr_expiry_label = document.createElement("label");
rr_expiry_label.setAttribute("for", "new_" + reagentRoles[i].id + "_expiry"); rr_expiry_label.setAttribute("for", "new_" + reagentRoles[i].id + "_expiry");
rr_expiry_label.innerHTML = "Expiry:"; rr_expiry_label.innerHTML = "Expiry:";
var submit_btn = document.createElement("input"); var submit_btn = document.createElement("input");
submit_btn.setAttribute("type", "submit"); submit_btn.setAttribute("type", "submit");
submit_btn.setAttribute("value", "Submit"); submit_btn.setAttribute("value", "Submit");
new_form.appendChild(br.cloneNode()); new_form.appendChild(br.cloneNode());
new_form.appendChild(rr_name_label); new_form.appendChild(rr_name_label);
new_form.appendChild(rr_name); new_form.appendChild(rr_name);
@@ -72,19 +66,27 @@ for(let i = 0; i < reagentRoles.length; i++) {
new_form.appendChild(br.cloneNode()); new_form.appendChild(br.cloneNode());
new_form.appendChild(submit_btn); new_form.appendChild(submit_btn);
new_form.appendChild(br.cloneNode()); new_form.appendChild(br.cloneNode());
new_form.onsubmit = function(event) { new_form.onsubmit = function(event) {
event.preventDefault(); event.preventDefault();
alert(reagentRoles[i].id);
name = document.getElementById("new_" + reagentRoles[i].id + "_name").value; name = document.getElementById("new_" + reagentRoles[i].id + "_name").value;
lot = document.getElementById("new_" + reagentRoles[i].id + "_lot").value; lot = document.getElementById("new_" + reagentRoles[i].id + "_lot").value;
expiry = document.getElementById("new_" + reagentRoles[i].id + "_expiry").value; expiry = document.getElementById("new_" + reagentRoles[i].id + "_expiry").value;
alert("Submitting: " + name + ", " + lot); backend.add_new_reagent(reagentRoles[i].id, name, lot, expiry);
backend.log(name + " " + lot + " " + expiry); new_form.remove();
reagentRoles[i].dispatchEvent(changed_it);
} }
new_reg.appendChild(new_form); new_reg.appendChild(new_form);
} else {
newregform = document.getElementById(reagentRoles[i].id + "_addition");
newregform.remove();
backend.update_reagent(reagentRoles[i].id, reagentRoles[i].value)
} }
}) });
}; };
window.onload = function() {
for(let i = 0; i < reagentRoles.length; i++) {
backend.update_reagent(reagentRoles[i].id, reagentRoles[i].value);
}
}

View File

@@ -31,12 +31,14 @@
{% endfor %} {% endfor %}
</select><br> </select><br>
{% if procedure['reagentrole'] %} {% if procedure['reagentrole'] %}
<br><hr><br> <br>
<h1><u>Reagents</u></h1>
<hr>
{% for key, value in procedure['reagentrole'].items() %} {% for key, value in procedure['reagentrole'].items() %}
<label for="{{ key }}">{{ key }}:</label><br> <label for="{{ key }}">{{ key }}:</label><br>
<select class="reagentrole dropdown" id="{{ key }}" name="{{ key }}"><br> <select class="reagentrole dropdown" id="{{ key }}" name="{{ key }}"><br>
{% for reagent in value %} {% for reagent in value %}
<option value="{{ reagent }}">{{ reagent }}</option> <option value="{{ reagent.name }} {% if reagent.lot %}- {{ reagent.lot }} - {{ reagent.expiry.date() }}{% endif %}">{{ reagent.name }} {% if reagent.lot %}- {{ reagent.lot }} - {{ reagent.expiry.date() }}{% endif %}</option>
{% endfor %} {% endfor %}
</select> </select>
<div class="new_reagent" id="new_{{ key }}"></div> <div class="new_reagent" id="new_{{ key }}"></div>