Added html links for equipment/processes/tips.
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
# 202504.04
|
||||||
|
|
||||||
|
- Added html links for equipment/processes/tips.
|
||||||
|
|
||||||
# 202504.03
|
# 202504.03
|
||||||
|
|
||||||
- Split Concentration controls on the chart so they are individually selectable.
|
- Split Concentration controls on the chart so they are individually selectable.
|
||||||
|
|||||||
4
TODO.md
4
TODO.md
@@ -1,3 +1,6 @@
|
|||||||
|
- [ ] transfer details template rendering fully into sql objects
|
||||||
|
- [x] Add in connecting links for tips.
|
||||||
|
- [x] Add in connecting links for equipment/processes.
|
||||||
- [ ] move functions from widgets.functions to... app?
|
- [ ] move functions from widgets.functions to... app?
|
||||||
- [x] Apply below fix to all other date-based queries.
|
- [x] Apply below fix to all other date-based queries.
|
||||||
- [x] Fix Control graph chart bug that excludes today's controls.
|
- [x] Fix Control graph chart bug that excludes today's controls.
|
||||||
@@ -12,7 +15,6 @@
|
|||||||
- [x] Upgrade to generators when returning lists.
|
- [x] Upgrade to generators when returning lists.
|
||||||
- [x] Revamp frontend.widgets.controls_chart to include visualizations?
|
- [x] Revamp frontend.widgets.controls_chart to include visualizations?
|
||||||
- [x] Convert Parsers to using openpyxl.
|
- [x] Convert Parsers to using openpyxl.
|
||||||
- The hardest part of this is going to be the sample parsing. I'm onto using the cell formulas in the plate map to suss out the location in the lookup table, but it could get a little recursive up in here.
|
|
||||||
- [ ] Create a default info return function.
|
- [ ] Create a default info return function.
|
||||||
- [x] Parse comment from excel sheet.
|
- [x] Parse comment from excel sheet.
|
||||||
- [x] Make reporting better.
|
- [x] Make reporting better.
|
||||||
|
|||||||
@@ -55,9 +55,10 @@ def update_log(mapper, connection, target):
|
|||||||
continue
|
continue
|
||||||
added = [str(item) for item in hist.added]
|
added = [str(item) for item in hist.added]
|
||||||
# NOTE: Attributes left out to save space
|
# NOTE: Attributes left out to save space
|
||||||
if attr.key in ['artic_technician', 'submission_sample_associations', 'submission_reagent_associations',
|
# if attr.key in ['artic_technician', 'submission_sample_associations', 'submission_reagent_associations',
|
||||||
'submission_equipment_associations', 'submission_tips_associations', 'contact_id', 'gel_info',
|
# 'submission_equipment_associations', 'submission_tips_associations', 'contact_id', 'gel_info',
|
||||||
'gel_controls', 'source_plates']:
|
# 'gel_controls', 'source_plates']:
|
||||||
|
if attr.key in LogMixin.tracking_exclusion:
|
||||||
continue
|
continue
|
||||||
deleted = [str(item) for item in hist.deleted]
|
deleted = [str(item) for item in hist.deleted]
|
||||||
change = dict(field=attr.key, added=added, deleted=deleted)
|
change = dict(field=attr.key, added=added, deleted=deleted)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from sqlalchemy import Column, INTEGER, String, JSON
|
|||||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, Query, Session, InstrumentedAttribute, ColumnProperty
|
from sqlalchemy.orm import DeclarativeMeta, declarative_base, Query, Session, InstrumentedAttribute, ColumnProperty
|
||||||
from sqlalchemy.ext.declarative import declared_attr
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from sqlalchemy.exc import ArgumentError
|
from sqlalchemy.exc import ArgumentError
|
||||||
from typing import Any, List
|
from typing import Any, List, ClassVar
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from sqlalchemy.orm.relationships import _RelationshipDeclared
|
from sqlalchemy.orm.relationships import _RelationshipDeclared
|
||||||
from tools import report_result, list_sort_dict
|
from tools import report_result, list_sort_dict
|
||||||
@@ -25,6 +25,12 @@ logger = logging.getLogger(f"submissions.{__name__}")
|
|||||||
|
|
||||||
|
|
||||||
class LogMixin(Base):
|
class LogMixin(Base):
|
||||||
|
|
||||||
|
tracking_exclusion: ClassVar = ['artic_technician', 'submission_sample_associations',
|
||||||
|
'submission_reagent_associations', 'submission_equipment_associations',
|
||||||
|
'submission_tips_associations', 'contact_id', 'gel_info', 'gel_controls',
|
||||||
|
'source_plates']
|
||||||
|
|
||||||
__abstract__ = True
|
__abstract__ = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ All kit and reagent related models
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json, zipfile, yaml, logging, re, sys
|
import json, zipfile, yaml, logging, re, sys
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
|
||||||
|
from jinja2 import Template, TemplateNotFound
|
||||||
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 sqlalchemy.ext.hybrid import hybrid_property
|
from sqlalchemy.ext.hybrid import hybrid_property
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from tools import check_authorization, setup_lookup, Report, Result, check_regex_match, yaml_regex_creator, timezone
|
from tools import check_authorization, setup_lookup, Report, Result, check_regex_match, yaml_regex_creator, timezone, \
|
||||||
|
jinja_template_loading
|
||||||
from typing import List, Literal, Generator, Any, Tuple
|
from typing import List, Literal, Generator, Any, Tuple
|
||||||
from pandas import ExcelFile
|
from pandas import ExcelFile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -2065,6 +2068,53 @@ class Equipment(BaseClass, LogMixin):
|
|||||||
output.append(equipment[choice])
|
output.append(equipment[choice])
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def to_sub_dict(self, full_data: bool = False, **kwargs) -> dict:
|
||||||
|
"""
|
||||||
|
dictionary containing values necessary for gui
|
||||||
|
|
||||||
|
Args:
|
||||||
|
full_data (bool, optional): Whether to include submissions in data for details. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: representation of the equipment's attributes
|
||||||
|
"""
|
||||||
|
if self.nickname:
|
||||||
|
nickname = self.nickname
|
||||||
|
else:
|
||||||
|
nickname = self.name
|
||||||
|
output = dict(
|
||||||
|
name=self.name,
|
||||||
|
nickname=nickname,
|
||||||
|
asset_number=self.asset_number
|
||||||
|
)
|
||||||
|
if full_data:
|
||||||
|
subs = []
|
||||||
|
output['submissions'] = [dict(plate=item.submission.rsl_plate_num, process=item.process.name)
|
||||||
|
if item.process else dict(plate=item.submission.rsl_plate_num, process="NA")
|
||||||
|
for item in self.equipment_submission_associations]
|
||||||
|
output['excluded'] = ['missing', 'submissions', 'excluded', 'editable']
|
||||||
|
return output
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def details_template(cls) -> Template:
|
||||||
|
"""
|
||||||
|
Get the details jinja template for the correct class
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_dict (dict): incoming dictionary of Submission fields
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple(dict, Template): (Updated dictionary, Template to be rendered)
|
||||||
|
"""
|
||||||
|
env = jinja_template_loading()
|
||||||
|
temp_name = f"{cls.__name__.lower()}_details.html"
|
||||||
|
try:
|
||||||
|
template = env.get_template(temp_name)
|
||||||
|
except TemplateNotFound as e:
|
||||||
|
logger.error(f"Couldn't find template {e}")
|
||||||
|
template = env.get_template("equipment_details.html")
|
||||||
|
return template
|
||||||
|
|
||||||
|
|
||||||
class EquipmentRole(BaseClass):
|
class EquipmentRole(BaseClass):
|
||||||
"""
|
"""
|
||||||
@@ -2219,6 +2269,10 @@ class SubmissionEquipmentAssociation(BaseClass):
|
|||||||
self.equipment = equipment
|
self.equipment = equipment
|
||||||
self.role = role
|
self.role = role
|
||||||
|
|
||||||
|
@property
|
||||||
|
def process(self):
|
||||||
|
return Process.query(id=self.process_id)
|
||||||
|
|
||||||
def to_sub_dict(self) -> dict:
|
def to_sub_dict(self) -> dict:
|
||||||
"""
|
"""
|
||||||
This SubmissionEquipmentAssociation as a dictionary
|
This SubmissionEquipmentAssociation as a dictionary
|
||||||
@@ -2433,6 +2487,44 @@ class Process(BaseClass):
|
|||||||
tip_roles=tip_roles
|
tip_roles=tip_roles
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_sub_dict(self, full_data: bool = False, **kwargs) -> dict:
|
||||||
|
"""
|
||||||
|
dictionary containing values necessary for gui
|
||||||
|
|
||||||
|
Args:
|
||||||
|
full_data (bool, optional): Whether to include submissions in data for details. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: representation of the equipment's attributes
|
||||||
|
"""
|
||||||
|
output = dict(
|
||||||
|
name=self.name,
|
||||||
|
)
|
||||||
|
if full_data:
|
||||||
|
output['submissions'] = [dict(plate=sub.submission.rsl_plate_num, equipment=sub.equipment.name) for sub in self.submissions]
|
||||||
|
output['excluded'] = ['missing', 'submissions', 'excluded', 'editable']
|
||||||
|
return output
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def details_template(cls) -> Template:
|
||||||
|
"""
|
||||||
|
Get the details jinja template for the correct class
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_dict (dict): incoming dictionary of Submission fields
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple(dict, Template): (Updated dictionary, Template to be rendered)
|
||||||
|
"""
|
||||||
|
env = jinja_template_loading()
|
||||||
|
temp_name = f"{cls.__name__.lower()}_details.html"
|
||||||
|
try:
|
||||||
|
template = env.get_template(temp_name)
|
||||||
|
except TemplateNotFound as e:
|
||||||
|
logger.error(f"Couldn't find template {e}")
|
||||||
|
template = env.get_template("process_details.html")
|
||||||
|
return template
|
||||||
|
|
||||||
|
|
||||||
class TipRole(BaseClass):
|
class TipRole(BaseClass):
|
||||||
"""
|
"""
|
||||||
@@ -2576,6 +2668,45 @@ class Tips(BaseClass, LogMixin):
|
|||||||
name=self.name
|
name=self.name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_sub_dict(self, full_data: bool = False, **kwargs) -> dict:
|
||||||
|
"""
|
||||||
|
dictionary containing values necessary for gui
|
||||||
|
|
||||||
|
Args:
|
||||||
|
full_data (bool, optional): Whether to include submissions in data for details. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: representation of the equipment's attributes
|
||||||
|
"""
|
||||||
|
output = dict(
|
||||||
|
name=self.name,
|
||||||
|
lot=self.lot,
|
||||||
|
)
|
||||||
|
if full_data:
|
||||||
|
output['submissions'] = [dict(plate=item.submission.rsl_plate_num, role=item.role_name)
|
||||||
|
for item in self.tips_submission_associations]
|
||||||
|
output['excluded'] = ['missing', 'submissions', 'excluded', 'editable']
|
||||||
|
return output
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def details_template(cls) -> Template:
|
||||||
|
"""
|
||||||
|
Get the details jinja template for the correct class
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_dict (dict): incoming dictionary of Submission fields
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple(dict, Template): (Updated dictionary, Template to be rendered)
|
||||||
|
"""
|
||||||
|
env = jinja_template_loading()
|
||||||
|
temp_name = f"{cls.__name__.lower()}_details.html"
|
||||||
|
try:
|
||||||
|
template = env.get_template(temp_name)
|
||||||
|
except TemplateNotFound as e:
|
||||||
|
logger.error(f"Couldn't find template {e}")
|
||||||
|
template = env.get_template("tips_details.html")
|
||||||
|
return template
|
||||||
|
|
||||||
class SubmissionTypeTipRoleAssociation(BaseClass):
|
class SubmissionTypeTipRoleAssociation(BaseClass):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ class CustomFigure(Figure):
|
|||||||
else:
|
else:
|
||||||
html += "<h1>No data was retrieved for the given parameters.</h1>"
|
html += "<h1>No data was retrieved for the given parameters.</h1>"
|
||||||
html += '</body></html>'
|
html += '</body></html>'
|
||||||
with open("test.html", "w", encoding="utf-8") as f:
|
# with open("test.html", "w", encoding="utf-8") as f:
|
||||||
f.write(html)
|
# f.write(html)
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from PyQt6.QtWebEngineWidgets import QWebEngineView
|
|||||||
from PyQt6.QtWebChannel import QWebChannel
|
from PyQt6.QtWebChannel import QWebChannel
|
||||||
from PyQt6.QtCore import Qt, pyqtSlot
|
from PyQt6.QtCore import Qt, pyqtSlot
|
||||||
from jinja2 import TemplateNotFound
|
from jinja2 import TemplateNotFound
|
||||||
from backend.db.models import BasicSubmission, BasicSample, Reagent, KitType
|
from backend.db.models import BasicSubmission, BasicSample, Reagent, KitType, Equipment, Process, Tips
|
||||||
from tools import is_power_user, jinja_template_loading, timezone, get_application_from_parent
|
from tools import is_power_user, jinja_template_loading, timezone, get_application_from_parent
|
||||||
from .functions import select_save_file, save_pdf
|
from .functions import select_save_file, save_pdf
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -84,6 +84,48 @@ class SubmissionDetails(QDialog):
|
|||||||
else:
|
else:
|
||||||
self.back.setEnabled(True)
|
self.back.setEnabled(True)
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def equipment_details(self, equipment: str | Equipment):
|
||||||
|
logger.debug(f"Equipment details")
|
||||||
|
if isinstance(equipment, str):
|
||||||
|
equipment = Equipment.query(name=equipment)
|
||||||
|
base_dict = equipment.to_sub_dict(full_data=True)
|
||||||
|
template = equipment.details_template
|
||||||
|
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(equipment=base_dict, css=css)
|
||||||
|
self.webview.setHtml(html)
|
||||||
|
self.setWindowTitle(f"Equipment Details - {equipment.name}")
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def process_details(self, process: str | Process):
|
||||||
|
logger.debug(f"Equipment details")
|
||||||
|
if isinstance(process, str):
|
||||||
|
process = Process.query(name=process)
|
||||||
|
base_dict = process.to_sub_dict(full_data=True)
|
||||||
|
template = process.details_template
|
||||||
|
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(process=base_dict, css=css)
|
||||||
|
self.webview.setHtml(html)
|
||||||
|
self.setWindowTitle(f"Process Details - {process.name}")
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def tips_details(self, tips: str | Tips):
|
||||||
|
logger.debug(f"Equipment details: {tips}")
|
||||||
|
if isinstance(tips, str):
|
||||||
|
tips = Tips.query(lot=tips)
|
||||||
|
base_dict = tips.to_sub_dict(full_data=True)
|
||||||
|
template = tips.details_template
|
||||||
|
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(tips=base_dict, css=css)
|
||||||
|
self.webview.setHtml(html)
|
||||||
|
self.setWindowTitle(f"Process Details - {tips.name}")
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def sample_details(self, sample: str | BasicSample):
|
def sample_details(self, sample: str | BasicSample):
|
||||||
"""
|
"""
|
||||||
@@ -103,8 +145,8 @@ class SubmissionDetails(QDialog):
|
|||||||
with open(template_path.joinpath("css", "styles.css"), "r") as f:
|
with open(template_path.joinpath("css", "styles.css"), "r") as f:
|
||||||
css = f.read()
|
css = f.read()
|
||||||
html = template.render(sample=base_dict, css=css)
|
html = template.render(sample=base_dict, css=css)
|
||||||
with open(f"{sample.submitter_id}.html", 'w') as f:
|
# with open(f"{sample.submitter_id}.html", 'w') as f:
|
||||||
f.write(html)
|
# f.write(html)
|
||||||
self.webview.setHtml(html)
|
self.webview.setHtml(html)
|
||||||
self.setWindowTitle(f"Sample Details - {sample.submitter_id}")
|
self.setWindowTitle(f"Sample Details - {sample.submitter_id}")
|
||||||
|
|
||||||
|
|||||||
@@ -20,19 +20,19 @@
|
|||||||
{% if sub['reagents'] %}
|
{% if sub['reagents'] %}
|
||||||
<h3><u>Reagents:</u></h3>
|
<h3><u>Reagents:</u></h3>
|
||||||
<p>{% for item in sub['reagents'] %}
|
<p>{% for item in sub['reagents'] %}
|
||||||
<b>{{ item['role'] }}</b>: <a class="data-link reagent" id="{{ item['lot'] }}">{{ item['lot'] }} (EXP: {{ item['expiry'] }})</a><br>
|
<b>{{ item['role'] }}:</b> <a class="data-link reagent" id="{{ item['lot'] }}">{{ item['lot'] }} (EXP: {{ item['expiry'] }})</a><br>
|
||||||
{% endfor %}</p>
|
{% endfor %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if sub['equipment'] %}
|
{% if sub['equipment'] %}
|
||||||
<h3><u>Equipment:</u></h3>
|
<h3><u>Equipment:</u></h3>
|
||||||
<p>{% for item in sub['equipment'] %}
|
<p>{% for item in sub['equipment'] %}
|
||||||
<b>{{ item['role'] }}:</b> {{ item['name'] }} ({{ item['asset_number'] }}): {{ item['processes'][0]|replace('\n\t', '<br> ') }}<br>
|
<b>{{ item['role'] }}:</b> <a class="data-link equipment" id="{{ item['name'] }}"> {{ item['name'] }} ({{ item['asset_number'] }})</a>: <a class="data-link process" id="{{ item['processes'][0]|replace('\n\t', '') }}">{{ item['processes'][0]|replace('\n\t', '<br> ') }}</a><br>
|
||||||
{% endfor %}</p>
|
{% endfor %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if sub['tips'] %}
|
{% if sub['tips'] %}
|
||||||
<h3><u>Tips:</u></h3>
|
<h3><u>Tips:</u></h3>
|
||||||
<p>{% for item in sub['tips'] %}
|
<p>{% for item in sub['tips'] %}
|
||||||
<b>{{ item['role'] }}:</b> {{ item['name'] }} ({{ item['lot'] }})<br>
|
<b>{{ item['role'] }}:</b> <a class="data-link tips" id="{{ item['lot'] }}">{{ item['name'] }} ({{ item['lot'] }})</a><br>
|
||||||
{% endfor %}</p>
|
{% endfor %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if sub['samples'] %}
|
{% if sub['samples'] %}
|
||||||
@@ -99,6 +99,33 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var equipmentSelection = document.getElementsByClassName('equipment');
|
||||||
|
|
||||||
|
for(let i = 0; i < equipmentSelection.length; i++) {
|
||||||
|
equipmentSelection[i].addEventListener("click", function() {
|
||||||
|
console.log(equipmentSelection[i].id);
|
||||||
|
backend.equipment_details(equipmentSelection[i].id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var processSelection = document.getElementsByClassName('process');
|
||||||
|
|
||||||
|
for(let i = 0; i < processSelection.length; i++) {
|
||||||
|
processSelection[i].addEventListener("click", function() {
|
||||||
|
console.log(processSelection[i].id);
|
||||||
|
backend.process_details(processSelection[i].id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var tipsSelection = document.getElementsByClassName('tips');
|
||||||
|
|
||||||
|
for(let i = 0; i < tipsSelection.length; i++) {
|
||||||
|
tipsSelection[i].addEventListener("click", function() {
|
||||||
|
console.log(tipsSelection[i].id);
|
||||||
|
backend.tips_details(tipsSelection[i].id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById("sign_btn").addEventListener("click", function(){
|
document.getElementById("sign_btn").addEventListener("click", function(){
|
||||||
backend.sign_off("{{ sub['plate_number'] }}");
|
backend.sign_off("{{ sub['plate_number'] }}");
|
||||||
});
|
});
|
||||||
|
|||||||
50
src/submissions/templates/equipment_details.html
Normal file
50
src/submissions/templates/equipment_details.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{% extends "details.html" %}
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<title>Equipment Details for {{ equipment['name'] }}</title>
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body %}
|
||||||
|
<h2><u>Equipment Details for {{ equipment['name'] }}</u></h2>
|
||||||
|
{{ super() }}
|
||||||
|
<p>{% for key, value in equipment.items() if key not in equipment['excluded'] %}
|
||||||
|
<!-- <b>{{ key | replace("_", " ") | title }}: </b>{% if permission and key in reagent['editable']%}<input type={% if key=='expiry' %}"date"{% else %}"text"{% endif %} id="{{ key }}" name="{{ key }}" value="{{ value }}">{% else %}{{ value }}{% endif %}<br>-->
|
||||||
|
<b>{{ key | replace("_", " ") | title }}: </b>{{ value }}<br>
|
||||||
|
{% endfor %}</p>
|
||||||
|
<!-- {% if permission %}-->
|
||||||
|
<!-- <button type="button" id="save_btn">Save</button>-->
|
||||||
|
<!-- {% endif %}-->
|
||||||
|
{% if equipment['submissions'] %}<h2>Submissions:</h2>
|
||||||
|
{% for submission in equipment['submissions'] %}
|
||||||
|
<p><b><a class="data-link" id="{{ submission['plate'] }}">{{ submission['plate'] }}:</a></b> <a class="data-link process" id="{{ submission['process'] }}">{{ submission['process'] }}</a></p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
{% block script %}
|
||||||
|
{{ super() }}
|
||||||
|
|
||||||
|
var processSelection = document.getElementsByClassName('process');
|
||||||
|
|
||||||
|
for(let i = 0; i < processSelection.length; i++) {
|
||||||
|
processSelection[i].addEventListener("click", function() {
|
||||||
|
console.log(processSelection[i].id);
|
||||||
|
backend.process_details(processSelection[i].id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{% for submission in equipment['submissions'] %}
|
||||||
|
document.getElementById("{{ submission }}").addEventListener("click", function(){
|
||||||
|
backend.submission_details("{{ submission }}");
|
||||||
|
});
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
backend.activate_export(false);
|
||||||
|
}, false);
|
||||||
|
{% endblock %}
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
49
src/submissions/templates/process_details.html
Normal file
49
src/submissions/templates/process_details.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{% extends "details.html" %}
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<title>Process Details for {{ process['name'] }}</title>
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body %}
|
||||||
|
<h2><u>Process Details for {{ process['name'] }}</u></h2>
|
||||||
|
{{ super() }}
|
||||||
|
<p>{% for key, value in process.items() if key not in process['excluded'] %}
|
||||||
|
<!-- <b>{{ key | replace("_", " ") | title }}: </b>{% if permission and key in reagent['editable']%}<input type={% if key=='expiry' %}"date"{% else %}"text"{% endif %} id="{{ key }}" name="{{ key }}" value="{{ value }}">{% else %}{{ value }}{% endif %}<br>-->
|
||||||
|
<b>{{ key | replace("_", " ") | title }}: </b>{{ value }}<br>
|
||||||
|
{% endfor %}</p>
|
||||||
|
<!-- {% if permission %}-->
|
||||||
|
<!-- <button type="button" id="save_btn">Save</button>-->
|
||||||
|
<!-- {% endif %}-->
|
||||||
|
{% if process['submissions'] %}<h2>Submissions:</h2>
|
||||||
|
{% for submission in process['submissions'] %}
|
||||||
|
<p><b><a class="data-link" id="{{ submission['plate'] }}">{{ submission['plate'] }}:</a></b><a class="data-link equipment" id="{{ submission['equipment'] }}">{{ submission['equipment'] }}</a></p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
{% block script %}
|
||||||
|
{{ super() }}
|
||||||
|
|
||||||
|
var equipmentSelection = document.getElementsByClassName('equipment');
|
||||||
|
|
||||||
|
for(let i = 0; i < equipmentSelection.length; i++) {
|
||||||
|
equipmentSelection[i].addEventListener("click", function() {
|
||||||
|
console.log(equipmentSelection[i].id);
|
||||||
|
backend.equipment_details(equipmentSelection[i].id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{% for submission in process['submissions'] %}
|
||||||
|
document.getElementById("{{ submission['plate'] }}").addEventListener("click", function(){
|
||||||
|
backend.submission_details("{{ submission['plate'] }}");
|
||||||
|
});
|
||||||
|
{% endfor %}
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
backend.activate_export(false);
|
||||||
|
}, false);
|
||||||
|
{% endblock %}
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
50
src/submissions/templates/tips_details.html
Normal file
50
src/submissions/templates/tips_details.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{% extends "details.html" %}
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<title>Tips Details for {{ tips['name'] }}</title>
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body %}
|
||||||
|
<h2><u>Tips Details for {{ tips['name'] }}</u></h2>
|
||||||
|
{{ super() }}
|
||||||
|
<p>{% for key, value in tips.items() if key not in tips['excluded'] %}
|
||||||
|
<!-- <b>{{ key | replace("_", " ") | title }}: </b>{% if permission and key in reagent['editable']%}<input type={% if key=='expiry' %}"date"{% else %}"text"{% endif %} id="{{ key }}" name="{{ key }}" value="{{ value }}">{% else %}{{ value }}{% endif %}<br>-->
|
||||||
|
<b>{{ key | replace("_", " ") | title }}: </b>{{ value }}<br>
|
||||||
|
{% endfor %}</p>
|
||||||
|
<!-- {% if permission %}-->
|
||||||
|
<!-- <button type="button" id="save_btn">Save</button>-->
|
||||||
|
<!-- {% endif %}-->
|
||||||
|
{% if tips['submissions'] %}<h2>Submissions:</h2>
|
||||||
|
{% for submission in tips['submissions'] %}
|
||||||
|
<p><b><a class="data-link" id="{{ submission['plate'] }}">{{ submission['plate'] }}:</a></b> <a class="data-link process" id="{{ submission['role'] }}">{{ submission['role'] }}</a></p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
{% block script %}
|
||||||
|
{{ super() }}
|
||||||
|
|
||||||
|
var processSelection = document.getElementsByClassName('process');
|
||||||
|
|
||||||
|
for(let i = 0; i < processSelection.length; i++) {
|
||||||
|
processSelection[i].addEventListener("click", function() {
|
||||||
|
console.log(processSelection[i].id);
|
||||||
|
backend.process_details(processSelection[i].id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{% for submission in tips['submissions'] %}
|
||||||
|
document.getElementById("{{ submission }}").addEventListener("click", function(){
|
||||||
|
backend.submission_details("{{ submission }}");
|
||||||
|
});
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
backend.activate_export(false);
|
||||||
|
}, false);
|
||||||
|
{% endblock %}
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -16,7 +16,8 @@ api_path = project_path.joinpath(".venv", "Scripts", "sphinx-apidoc").absolute()
|
|||||||
subprocess.run([api_path, "-o", doc_path.joinpath("source").__str__(), project_path.joinpath("src", "submissions").__str__(), "-f"])
|
subprocess.run([api_path, "-o", doc_path.joinpath("source").__str__(), project_path.joinpath("src", "submissions").__str__(), "-f"])
|
||||||
print(bcolors.BOLD + "Running Sphinx subprocess to generate html docs..." + bcolors.ENDC)
|
print(bcolors.BOLD + "Running Sphinx subprocess to generate html docs..." + bcolors.ENDC)
|
||||||
docs_build = doc_path.joinpath("build")
|
docs_build = doc_path.joinpath("build")
|
||||||
#docs_build.mkdir(exist_ok=True, parents=True)
|
if not docs_build.exists():
|
||||||
|
docs_build.mkdir(exist_ok=True, parents=True)
|
||||||
subprocess.run([build_path, doc_path.joinpath("source").__str__(), docs_build.__str__(), "-a"])
|
subprocess.run([build_path, doc_path.joinpath("source").__str__(), docs_build.__str__(), "-a"])
|
||||||
|
|
||||||
#########################################################
|
#########################################################
|
||||||
|
|||||||
Reference in New Issue
Block a user