From 10ef3ced9a1ac64d70cb2f6c03dbbae6deeb4f3e Mon Sep 17 00:00:00 2001 From: Lingxin Meng Date: Wed, 16 Jul 2025 16:32:06 +0100 Subject: [PATCH 01/11] fix reference before assignment --- viewer/pages/qc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/viewer/pages/qc.py b/viewer/pages/qc.py index 468d1ea2b..60605589b 100644 --- a/viewer/pages/qc.py +++ b/viewer/pages/qc.py @@ -679,8 +679,8 @@ def recycle_analysis_core(test_run_id: str) -> tuple(str, str): except Exception as exc: logger.error(str(exc)) logger.error(traceback.format_exc()) - create_message( - f"failure in reycle_analysis()
{traceback.format_exc()}
", + msg = create_message( + f"failure in recycle_analysis()
{traceback.format_exc()}
", function="recycle_analysis", component=serial_number, code="RECYCLE_ANALYSIS", -- GitLab From d85aa78e1813fc19ed6370f3bfea61e71552998a Mon Sep 17 00:00:00 2001 From: Lingxin Meng Date: Wed, 16 Jul 2025 18:27:46 +0100 Subject: [PATCH 02/11] dynamically sized textarea for SN input --- viewer/templates/download_component.html | 25 ++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/viewer/templates/download_component.html b/viewer/templates/download_component.html index 3379e1da8..db134780e 100644 --- a/viewer/templates/download_component.html +++ b/viewer/templates/download_component.html @@ -16,6 +16,10 @@ border-right-style: dotted; border-right-color: #e1e1e1; } + .auto_height { + /* CSS */ + width: 100%; + } {% extends "layout.html" %} @@ -64,9 +68,18 @@ >

- +
- +
@@ -135,5 +148,13 @@ }); }); }); + + // dynamically update the height of the textarea + // https://stackoverflow.com/questions/6262472/multiple-lines-of-input-in-input-type-text + function auto_height(elem) { + /* javascript */ + elem.style.height = "1px"; + elem.style.height = `${elem.scrollHeight}px`; + } {% endblock %} -- GitLab From c1ac057c498ef6f6a1af3120fcb83787272f0cd1 Mon Sep 17 00:00:00 2001 From: Lingxin Meng Date: Wed, 16 Jul 2025 18:28:12 +0100 Subject: [PATCH 03/11] loop over component_ids --- viewer/pages/user.py | 147 ++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 70 deletions(-) diff --git a/viewer/pages/user.py b/viewer/pages/user.py index 391cafdd7..01ffb20d5 100755 --- a/viewer/pages/user.py +++ b/viewer/pages/user.py @@ -5,6 +5,7 @@ import hashlib import logging import os import secrets +import shlex import shutil import string import traceback @@ -349,90 +350,96 @@ def download_component(): code1 = request.form.get("code1", "") code2 = request.form.get("code2", "") - component_id = request.form.get("component_id") + component_ids = request.form.get("component_ids") skip_attachments = "skipAtt" in request.form.get("stage", "input").split("|") skip_synched = "noSkipSynched" not in request.form.get("stage", "input").split("|") if stage == "submit": - logger.info("start") - msg = f"stage = {stage}, component_id = {component_id}, skip_attachments = {skip_attachments}, skip_synched = {skip_synched}" - logger.info(msg) - - flag, client = process_request(code1, code2) - - if flag == 0: - stage = "input" - create_message( - "ITkPD not authorized. Please input correct codes.", - function="download_component", - code="ITKPD_AUTH", - level="error", - emit=False, - ) - - elif stage == "submit": - institution = session["institution"] - - if message_exists(component=component_id, code="START_SYNC_COMPONENT"): - logger.error("Already pulling this component.") + component_ids = shlex.shlex(component_ids) + component_ids.whitespace += "," + component_ids.whitespace += ";" + component_ids.whitespace_split = True + logger.info(f"component_ids {component_ids}") + for component_id in component_ids: + logger.info("start") + msg = f"stage = {stage}, component_id = {component_id}, skip_attachments = {skip_attachments}, skip_synched = {skip_synched}" + logger.info(msg) + + flag, client = process_request(code1, code2) + + if flag == 0: stage = "input" create_message( - f"The component {component_id} is already being pulled.", + "ITkPD not authorized. Please input correct codes.", function="download_component", - code="DUPLICATE", + code="ITKPD_AUTH", level="error", emit=False, ) - else: - timestamp = datetime.now() - ticket_id = create_message( - f"Recursive synchronization of the component {component_id} started on {timestamp}. This process will take several minutes to complete.", - function="RecursiveComponentsSynchronizer", - component=component_id, - code="START_SYNC_COMPONENT", - level="info", - ) - component_uri = url_for( - "component_api.show_component_sn", serialNumber=component_id - ) + elif stage == "submit": + institution = session["institution"] + + if message_exists(component=component_id, code="START_SYNC_COMPONENT"): + logger.error("Already pulling this component.") + stage = "input" + create_message( + f"The component {component_id} is already being pulled.", + function="download_component", + code="DUPLICATE", + level="error", + emit=False, + ) + else: + timestamp = datetime.now() + ticket_id = create_message( + f"Recursive synchronization of the component {component_id} started on {timestamp}. This process will take several minutes to complete.", + function="RecursiveComponentsSynchronizer", + component=component_id, + code="START_SYNC_COMPONENT", + level="info", + ) - def download_done(future): - clear_message({"_id": ticket_id}, forced=True) - try: - future.result() - emit_message( - f'Download finished for {component_id}', - "Successful Sync", - level="success", - ) - except Exception as e: - logger.error(f"{e}") - logger.error(traceback.format_exc()) - create_message( - "An error occurred in downloading {component_id}. Please check logs and contact LocalDB admin.", - function="download_component", - component=component_id, - code="GENERAL", - level="error", - ) - - executor = concurrent.futures.ThreadPoolExecutor( - thread_name_prefix="downloadComponent" - ) - future = executor.submit( - download_worker, - component_id, - code1, - code2, - skip_attachments, - skip_synched, - institution, - ) - future.add_done_callback(download_done) - executor.shutdown(wait=False) + component_uri = url_for( + "component_api.show_component_sn", serialNumber=component_id + ) + + def download_done(future, component_id=component_id): + clear_message({"_id": ticket_id}, forced=True) + try: + future.result() + emit_message( + f'Download finished for {component_id}', + "Successful Sync", + level="success", + ) + except Exception as e: + logger.error(f"{e}") + logger.error(traceback.format_exc()) + create_message( + f"An error occurred in downloading {component_id}. Please check logs and contact LocalDB admin.", + function="download_component", + component=component_id, + code="GENERAL", + level="error", + ) + + executor = concurrent.futures.ThreadPoolExecutor( + thread_name_prefix="downloadComponent" + ) + future = executor.submit( + download_worker, + component_id, + code1, + code2, + skip_attachments, + skip_synched, + institution, + ) + future.add_done_callback(download_done) + executor.shutdown(wait=False) table_docs = { "messages": format_messages( -- GitLab From 6a704c4da85024c591f76e66aafe8e54af85f565 Mon Sep 17 00:00:00 2001 From: Lingxin Meng Date: Wed, 16 Jul 2025 19:03:55 +0100 Subject: [PATCH 04/11] pre-commit B023 Function definition does not bind loop variable --- viewer/pages/user.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/viewer/pages/user.py b/viewer/pages/user.py index 01ffb20d5..c2e10e11a 100755 --- a/viewer/pages/user.py +++ b/viewer/pages/user.py @@ -406,7 +406,12 @@ def download_component(): "component_api.show_component_sn", serialNumber=component_id ) - def download_done(future, component_id=component_id): + def download_done( + future, + ticket_id=ticket_id, + component_uri=component_uri, + component_id=component_id, + ): clear_message({"_id": ticket_id}, forced=True) try: future.result() -- GitLab From 0f66417cbc65fc24995342927de591897cc94fd6 Mon Sep 17 00:00:00 2001 From: Lingxin Meng Date: Wed, 16 Jul 2025 21:41:36 +0000 Subject: [PATCH 05/11] Apply 2 suggestion(s) to 1 file(s) Co-authored-by: Giordon Holtsberg Stark --- viewer/templates/download_component.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/viewer/templates/download_component.html b/viewer/templates/download_component.html index db134780e..a00772673 100644 --- a/viewer/templates/download_component.html +++ b/viewer/templates/download_component.html @@ -16,10 +16,6 @@ border-right-style: dotted; border-right-color: #e1e1e1; } - .auto_height { - /* CSS */ - width: 100%; - } {% extends "layout.html" %} @@ -72,7 +68,7 @@
+ placeholder="Enter serial numbers..." + id="serialNumbersInput" + class="form-control" + value="{{ component_ids }}" + />
@@ -133,7 +130,14 @@ {% block javascript %} {% endblock %} diff --git a/viewer/templates/parts/head.html b/viewer/templates/parts/head.html index e16d7711d..8f0cce276 100644 --- a/viewer/templates/parts/head.html +++ b/viewer/templates/parts/head.html @@ -15,4 +15,5 @@ + diff --git a/viewer/templates/parts/loader.html b/viewer/templates/parts/loader.html index f17a26718..9db83204b 100644 --- a/viewer/templates/parts/loader.html +++ b/viewer/templates/parts/loader.html @@ -11,6 +11,8 @@ + + -- GitLab From 4360424cd857ff17027f589ea68d09d3b8acc005 Mon Sep 17 00:00:00 2001 From: Giordon Stark Date: Thu, 17 Jul 2025 08:15:31 -0700 Subject: [PATCH 11/11] try \n as well and \r --- viewer/templates/download_component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viewer/templates/download_component.html b/viewer/templates/download_component.html index 9b76143fb..e4fd8ac43 100644 --- a/viewer/templates/download_component.html +++ b/viewer/templates/download_component.html @@ -135,7 +135,7 @@ const input = document.querySelector("#serialNumbersInput"); new Tagify(input, { enforceWhitelist: false, - delimiters: ",; ", // comma, semi-colon, or space separated + delimiters: ",|;| |\n|\r", // delimiters are regex pattern: /^20U[A-Z]{2}[A-Z0-9]{2}[0-9]{7}$/, }); -- GitLab