From bec2896e64eb0ecd0add7134ff91e0a357575b76 Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Wed, 20 Jul 2022 19:29:40 +0900
Subject: [PATCH 1/7] listing PCBs and bare modules

---
 viewer/functions/common.py             |  81 ++++++++
 viewer/pages/#tag.py#                  | 126 ++++++++++++
 viewer/pages/component.py              |   5 +-
 viewer/pages/tag.py                    |   6 +
 viewer/pages/toppage.py                | 258 ++++++++++++++++++++-----
 viewer/templates/500.html              |  12 +-
 viewer/templates/components_table.html | 103 ++++------
 viewer/templates/parts/nav.html        |  10 +-
 viewer/templates/scan_table.html       |   2 +-
 viewer/templates/toppage.html          |   7 +-
 10 files changed, 493 insertions(+), 117 deletions(-)
 create mode 100755 viewer/pages/#tag.py#

diff --git a/viewer/functions/common.py b/viewer/functions/common.py
index 76d3a969..321ab4ef 100755
--- a/viewer/functions/common.py
+++ b/viewer/functions/common.py
@@ -613,3 +613,84 @@ def delim_SN( sn ):
         return ' '.join( [ sn[0:3], sn[3:7], sn[7:9], sn[9:] ] )
     else:
         return sn
+
+
+def SN_typeinfo( sn ):
+    if sn.find( '20U' ) == 0:
+        
+        if sn[:7] == '20UPGFC':
+            try:
+                hexName  = "{0:#0{1}x}".format(int( name[-7:] ),7)
+            except:
+                pass
+                
+            batchMap = { '0':'RD53A', '1':'ITkPix' }
+            
+            typeinfo = 'Undef'
+            try:
+                typeinfo = batchMap[hexName[2]]
+            except:
+                pass
+        
+            wafer= '-{}-({},{})'.format( hexName[3:4], hexName[5], hexName[6] )
+            
+            typeinfo += wafer
+            
+            
+        elif sn.find( '20UPGXF' ) == 0:
+            typeinfo = 'Tutorial-FE'
+        elif sn.find( '20UPGXB' ) == 0:
+            typeinfo = 'Tutorial-BareModule'
+        elif sn.find( '20UPGXP' ) == 0:
+            typeinfo = 'Tutorial-PCB'
+        elif sn.find( '20UPGPQ' ) == 0:
+            typeinfo = 'QuadPCB'
+        elif sn.find( '20UPGPD' ) == 0:
+            typeinfo = 'DualPCB'
+        elif sn.find( '20UPIPT' ) == 0:
+            typeinfo = 'TripletL0StavePCB'
+        elif sn.find( '20UPIP0' ) == 0:
+            typeinfo = 'TripletL0R0PCB'
+        elif sn.find( '20UPIP5' ) == 0:
+            typeinfo = 'TripletL0R0.5PCB'
+        elif sn.find( '20UPGB1' ) == 0:
+            typeinfo = 'Single-BareModule'
+        elif sn.find( '20UPGB2' ) == 0:
+            typeinfo = 'Dual-BareModule'
+        elif sn.find( '20UPGB4' ) == 0:
+            typeinfo = 'Quad-BareModule'
+        elif sn.find( '20UPGBS' ) == 0:
+            typeinfo = 'Digital-Single-BareModule'
+        elif sn.find( '20UPGBQ' ) == 0:
+            typeinfo = 'Digital-Quad-BareModule'
+        elif 'PI' in sn:
+            typeinfo = "L0/L1 Inner Module"
+        elif 'PB' in sn:
+            typeinfo = "Outer Barrel Module"
+        elif 'PE' in sn:
+            typeinfo = "Outer Endcap Module"
+        elif 'PGM2' in sn:
+            typeinfo = "Outer Quad Module"
+        elif 'PGR2' in sn:
+            typeinfo = "Dual Chip Module"
+        elif 'PGR0' in sn:
+            typeinfo = "Single Chip Module"
+        elif 'XM' in sn:
+            typeinfo = "Tutorial Module"
+        else:
+            typeinfo = "Others"
+            
+        if 'Module' in typeinfo:
+            if   '0' == sn[7]:
+                typeinfo+= ' / RD53A'
+            elif '1' == sn[7]:
+                typeinfo+=' / ITkPix_v1.0'
+            elif '2' == sn[7]:
+                typeinfo+=' / ITkPix_v1.1'
+            elif '3' == sn[7]:
+                typeinfo+=' / ITkPix_v2'
+                
+        return typeinfo
+    else:
+        return ""
+    
diff --git a/viewer/pages/#tag.py# b/viewer/pages/#tag.py#
new file mode 100755
index 00000000..b5e92050
--- /dev/null
+++ b/viewer/pages/#tag.py#
@@ -0,0 +1,126 @@
+from functions.imports import *
+
+tag_api = Blueprint("tag_api", __name__)
+
+@tag_api.route("/create_tag", methods=["GET", "POST"])
+def create_tag():
+    stage = request.form.get("stage", "input")
+
+    if not session.get("logged_in", False):
+        return render_template( "401.html" )
+
+    taginfo = request.form.getlist("taginfo")
+    if taginfo == []:
+        session.pop("tag", None)
+
+    if session.get("tag", None):
+        query = {"name": taginfo[0]}
+        thistime = datetime.utcnow()
+        tags = userdb.viewer.tag.categories.find(query)
+
+        if not tags.count() == 0:
+            text = "This tag is already in use, please input an alternative."
+            stage = "input"
+            return render_template(
+                "create_tag.html",
+                tagInfo=taginfo,
+                nametext=text,
+                stage=stage,
+                timezones=pytz.all_timezones,
+            )
+        if stage == "input":
+            return render_template(
+                "create_tag.html",
+                tagInfo=taginfo,
+                stage=stage,
+                timezones=pytz.all_timezones,
+            )
+        elif stage == "confirm":
+            return render_template(
+                "create_tag.html",
+                tagInfo=taginfo,
+                stage=stage,
+                timezones=pytz.all_timezones,
+            )
+        else:
+            userdb.viewer.tag.categories.insert_one(
+                {
+                    "sys": {"rev": 0, "cts": thistime, "mts": thistime},
+                    "name": taginfo[0],
+                    "user_id": session["user_id"],
+                }
+            )
+
+            session.pop("tag")
+            return render_template(
+                "create_tag.html",
+                tagInfo=taginfo,
+                stage=stage,
+                timezones=pytz.all_timezones,
+            )
+
+    taginfo = [""]
+    pre_url = request.headers.get("Referer")
+    session["pre_url"] = pre_url
+
+    session["tag"] = True
+
+    return render_template(
+        "create_tag.html", tagInfo=taginfo, stage=stage, timezones=pytz.all_timezones
+    )
+
+@tag_api.route("/put_tag", methods=["GET", "POST"])
+def put_tag():
+    thistime = datetime.utcnow()
+    # tag_name = request.args.get('tag_name')
+    tag_name = request.form.get("tag_name")
+    tagdocs = {
+        "sys": {"rev": 0, "cts": thistime, "mts": thistime},
+        "name": tag_name,
+        "user_id": session["user_id"],
+    }
+    componentid = request.args.get("componentid", -1)
+    runId = request.args.get("runId", -1)
+
+    if not componentid == -1:
+        query = {"name": tag_name, "componentid": componentid}
+        tags = userdb.viewer.tag.docs.find(query)
+        if tags.count() == 0:
+            componentid = {
+                "componentid": componentid,
+            }
+            tagdocs.update(componentid)
+            userdb.viewer.tag.docs.insert(tagdocs)
+        else:
+            userdb.viewer.tag.docs.remove(query)
+
+    if not runId == -1:
+        query = {"name": tag_name, "runId": runId}
+        tags = userdb.viewer.tag.docs.find(query)
+        if tags.count() == 0:
+            query_doc = userdb.viewer.query.find_one({"runId": runId})
+            new_list = query_doc["data"]
+            new_list.append(str(tag_name))
+            userdb.viewer.query.update({"runId": runId}, {"$set": {"data": new_list}})
+            runId = {
+                "runId": runId,
+            }
+            tagdocs.update(runId)
+            userdb.viewer.tag.docs.insert(tagdocs)
+        else:
+            query_doc = userdb.viewer.query.find_one({"runId": runId})
+            new_list = query_doc["data"]
+            new_list.remove(str(tag_name))
+            userdb.viewer.query.update({"runId": runId}, {"$set": {"data": new_list}})
+            userdb.viewer.tag.docs.remove(query)
+
+    return redirect(request.headers.get("Referer"))
+
+
+
+@tag_api.route("/archive", methods=["GET", "POST"])
+def archive():
+    return render_template(
+        "toppage.html", tagInfo=taginfo, stage=stage, timezones=pytz.all_timezones
+    )
+
diff --git a/viewer/pages/component.py b/viewer/pages/component.py
index a04b1a8d..9464c629 100755
--- a/viewer/pages/component.py
+++ b/viewer/pages/component.py
@@ -871,7 +871,10 @@ def setComponentInfo(i_oid, i_col):
     ### component
     query = {"_id": ObjectId(i_oid)}
     this = localdb[i_col].find_one(query)
-    qc_doc = localdb.QC.module.status.find_one( { "component": i_oid,"proddbVersion":proddbv } )
+    qc_doc = localdb.QC.module.status.find_one( { "component": i_oid } )
+    logger.info( '{}'.format( { "component": i_oid } ) )
+    logger.info( '{}'.format( qc_doc ) )
+    
     if qc_doc == None: qc_doc = {}
     session["unit"] = this["componentType"].lower()  ### TODO wakarinikui
     docs = {
diff --git a/viewer/pages/tag.py b/viewer/pages/tag.py
index 7bc82c4e..a0346ce2 100755
--- a/viewer/pages/tag.py
+++ b/viewer/pages/tag.py
@@ -115,3 +115,9 @@ def put_tag():
             userdb.viewer.tag.docs.remove(query)
 
     return redirect(request.headers.get("Referer"))
+
+
+
+@tag_api.route("/archive", methods=["GET", "POST"])
+def archive():
+    return
diff --git a/viewer/pages/toppage.py b/viewer/pages/toppage.py
index 247be723..d211b3bb 100755
--- a/viewer/pages/toppage.py
+++ b/viewer/pages/toppage.py
@@ -64,7 +64,7 @@ def show_toppage():
 def show_comps():
     initPage()
 
-    table_docs = {"components": { "modules":[] } }
+    table_docs = {"components": [] }
 
     # get keywords
     if not request.form.get("keywords") == None:
@@ -74,7 +74,14 @@ def show_comps():
         table_docs["keywords"] = request.args.get("keywords", "")
         table_docs["match"] = request.args.get("match", "None")
         
-    table_docs['view'] = request.args.get("componentType", "module")
+    table_docs['view'] = request.args.get("view", None)
+    
+    if table_docs['view'] == None:
+        table_docs['view'] = request.form.get("view", "module")
+    
+    view = table_docs['view']
+    
+    logger.debug('show_comps(): view = {}'.format( view ) )
 
     compsPerPage = 10
     
@@ -82,24 +89,165 @@ def show_comps():
     if not request.args.get("p", 1) == "":
         page = int(request.args.get("p", 1))
 
-    query = {"dbVersion": dbv}
-    entries = localdb.component.find(query)
+    components = localdb.component.find( {"dbVersion": dbv, "componentType":view } )
     cmp_ids = []
-    for entry in entries:
-        cmp_ids.append(str(entry["_id"]))
+    for component in components:
+        
+        # logger.info( 'component: {}'.format( component ) )
+        
+        cmp_id = str(component["_id"])
+        
+        cmp_ids.append( cmp_id )
+        
+        
+        cps = []
+        
+        cprs1 = localdb.childParentRelation.find( { "parent":cmp_id } )
+        cprs2 = localdb.childParentRelation.find( { "child":cmp_id } )
+        
+        for cpr in cprs1:
+        
+            child = localdb.component.find_one( { "_id":ObjectId( cpr['child'] ) } )
+            
+            # logger.info( 'child = {}'.format( child ) )
+            
+            child_name = child['name']
+            
+            typeinfo = SN_typeinfo( child_name )
+            
+            cps.append(
+                {"_id": str( child["_id"] ),
+                 "collection": "component",
+                 "name": delim_SN( child['name'] ),
+                 "name_orig": child['name'],
+                 "grade": {},
+                 "hex" : hexName if child_name.find('20UPGFC')==0 else '',
+                 "typeinfo" : typeinfo
+             } )
+            
+        # endfor
+            
+        for cpr in cprs2:
+        
+            parent = localdb.component.find_one( { "_id":ObjectId( cpr['parent'] ) } )
+            
+            # logger.info( 'parent = {}'.format( parent ) )
+            
+            parent_name = parent['name']
+            
+            typeinfo = SN_typeinfo( parent_name )
+            
+            cps.append(
+                {"_id": str( parent["_id"] ),
+                 "collection": "component",
+                 "name": delim_SN( parent['name'] ),
+                 "name_orig": parent['name'],
+                 "grade": {},
+                 "hex" : hexName if parent_name.find('20UPGFC')==0 else '',
+                 "typeinfo" : typeinfo
+             } )
+            
+        # endfor
+            
+        name = component['name']
+        
+        typeinfo = SN_typeinfo( name )
+        
+        qcStatus = localdb.QC.module.status.find_one( {"component": cmp_id} )
+        
+        result = localdb.QC.result.find_one( {"component": cmp_id} )
 
+        ### tags
+        query = {}
+        module_tag_candidates = userdb.viewer.tag.categories.find(query)
+        tag_candidate = []
+        for module_tag in module_tag_candidates:
+            tag_candidate.append(module_tag)
+        ### put tags
+        query = {"componentid": cmp_id}
+        module_tags = userdb.viewer.tag.docs.find(query)
+        tag = []
+        for module_tag in module_tags:
+            tag.append(module_tag)
+        
+        component_data = {
+            "_id": cmp_id,
+            "collection": "component",
+            "name": delim_SN( name ),
+            "name_orig": name,
+            "typeinfo": typeinfo,
+            "cps": cps,
+            "grade": {},
+            "proDB": component.get("proDB", False),
+            "component_tag_candidate": tag_candidate,
+            "component_tag": tag,
+        }
+        
+        if qcStatus:
+            component_data.update( { "stage":qcStatus["currentStage"] } )
+        
+        if result:
+            component_data.update( {
+                "runId": str( result["_id"] ),
+                "datetime": setTime( result["sys"]["cts"], session.get("timezone", str(get_localzone()) ) ),
+                "testType": result["testType"],
+                "user": result["user"],
+                "site": result["address"]    } )
+            
+        logger.debug( 'data: {}'.format( component_data ) )
+        
+        # component search field
+        search_targets = []
+        search_targets.append(component_data["name_orig"])
+        if 'stage'    in component_data: search_targets.append(component_data["stage"])
+        if 'user'     in component_data: search_targets.append(component_data["user"])
+        if 'site'     in component_data: search_targets.append(component_data["site"])
+        if 'datetime' in component_data: search_targets.append(component_data["datetime"])
+        
+        for tag in component_data["component_tag"]:
+            search_targets.append(tag["name"])
+            
+        for subcomp in component_data["cps"]:
+            search_targets.append(subcomp["name_orig"])
+            
+        isKeywordMatched = query_keywords(
+            table_docs["keywords"], search_targets, table_docs["match"]
+        )
+        
+        if isKeywordMatched:
+            table_docs["components"].append( component_data )
+        
+        
+    #end for component in components:
+    
     pageMinIndex = compsPerPage * (page-1)
     pageMaxIndex = compsPerPage * page
     
-    table_docs["components"].update(
-        {
-            "modules": [],
-            "module_num": 0,
-            "chips": [],
-            "chip_num": 0
-        }
+    nModulesTotal = len( table_docs['components'] )
+    maxPage = len( table_docs['components'] ) // compsPerPage + 1
+    minRange = max(1, page - 2)
+    maxRange = min(maxPage, minRange+3)
+    pageRange = list( range( minRange, maxRange+1 ) )
+
+    pagingInfo = {
+        "thisPage": page,
+        "range" : pageRange,
+        "minPage": 1,
+        "maxPage": maxPage,
+        "entries" : nModulesTotal
+    }
+    
+    table_docs.update( { 'pagingInfo':pagingInfo } )
+    table_docs["page"] = "components"
+    table_docs["title"] = "Component List"
+    table_docs["download_module"] = os.path.exists(IF_DIR+"/doing_download.txt")
+    
+    return render_template(
+        "toppage.html", table_docs=table_docs, timezones=pytz.all_timezones
     )
 
+    #######----------------------------------------------------------------------------------------------
+
     # Filter modules
     index = 0
     for cmp_id in cmp_ids:
@@ -112,20 +260,14 @@ def show_comps():
             query = {"parent": cmp_id}
         else:
             continue
-        '''
-        elif this_cmp.get("componentType", "front-end_chip").lower() == "front-end_chip" :
-            key = "chips"
-            id_key = "parent"
-            query = {"child": cmp_id}
-        '''
         
         index += 1
 
         ### cpr entries
-        entries = localdb.childParentRelation.find(query)
+        components = localdb.childParentRelation.find(query)
         cpr_ids = []
-        for entry in entries:
-            cpr_ids.append(entry[id_key])
+        for component in components:
+            cpr_ids.append(component[id_key])
         cps = []
         for cpr_id in cpr_ids:
             query = {"_id": ObjectId(cpr_id)}
@@ -137,7 +279,7 @@ def show_comps():
                     name = this_cp["serialNumber"]
 
                 hexName = ''
-                if name.find('20UP') == 0:
+                if name.find('20U') == 0:
                     try:
                         hexName  = "{0:#0{1}x}".format(int( name[-7:] ),7)
                     except:
@@ -145,41 +287,70 @@ def show_comps():
 
                 batchMap = { '0':'RD53A', '1':'ITkPix' }
                 
-                fetype = 'Undef'
+                typeinfo = 'Undef'
                 try:
-                    fetype = batchMap[hexName[2]]
+                    typeinfo = batchMap[hexName[2]]
                 except:
                     pass
                     
+                if 'PI' in name:
+                    typeinfo = "L0/L1 Inner Module"
+                elif 'PB' in name:
+                    typeinfo = "Outer Barrel Module"
+                elif 'PE' in name:
+                    typeinfo = "Outer Endcap Module"
+                elif 'PGM2' in name:
+                    typeinfo = "Outer Quad Module"
+                elif 'PGR2' in name:
+                    typeinfo = "Dual Chip Module"
+                elif 'PGR-' in name:
+                    typeinfo = "Single Chip Module"
+                elif 'XM' in name:
+                    typeinfo = "Tutorial Module"
+                else:
+                    typeinfo = "Others"
+                    
+                    
+                if   '0' == name[7]:
+                    typeinfo+= ' / RD53A'
+                elif '1' == name[7]:
+                    typeinfo+=' / ITkPix_v1.0'
+                elif '2' == name[7]:
+                    typeinfo+=' / ITkPix_v1.1'
+                elif '3' == name[7]:
+                    typeinfo+=' / ITkPix_v2'
+                    
+                    
                 wafer=''
                 if name.find('20UPGFC') == 0:
                     wafer= '-{}-({},{})'.format( hexName[3:4], hexName[5], hexName[6] )
-                elif name.find( '20UPGXF' ) == 0:
-                    fetype = 'Tutorial-FE'
+                    
+                if name.find( '20UPGXF' ) == 0:
+                    typeinfo = 'Tutorial-FE'
                 elif name.find( '20UPGXB' ) == 0:
-                    fetype = 'Tutorial-BareModule'
+                    typeinfo = 'Tutorial-BareModule'
                 elif name.find( '20UPGXP' ) == 0:
-                    fetype = 'Tutorial-PCB'
+                    typeinfo = 'Tutorial-PCB'
                 elif name.find( '20UPGPQ' ) == 0:
-                    fetype = 'QuadPCB'
+                    typeinfo = 'QuadPCB'
                 elif name.find( '20UPGPD' ) == 0:
-                    fetype = 'DualPCB'
+                    typeinfo = 'DualPCB'
                 elif name.find( '20UPIPT' ) == 0:
-                    fetype = 'TripletL0StavePCB'
+                    typeinfo = 'TripletL0StavePCB'
                 elif name.find( '20UPIP0' ) == 0:
-                    fetype = 'TripletL0R0PCB'
+                    typeinfo = 'TripletL0R0PCB'
                 elif name.find( '20UPIP5' ) == 0:
-                    fetype = 'TripletL0R0.5PCB'
+                    typeinfo = 'TripletL0R0.5PCB'
                 elif name.find( '20UPGB1' ) == 0:
-                    fetype = 'Single-BareModule'
+                    typeinfo = 'Single-BareModule'
                 elif name.find( '20UPGB2' ) == 0:
-                    fetype = 'Dual-BareModule'
+                    typeinfo = 'Dual-BareModule'
                 elif name.find( '20UPGB4' ) == 0:
-                    fetype = 'Quad-BareModule'
+                    typeinfo = 'Quad-BareModule'
                 elif name.find( '20UPGBS' ) == 0:
-                    fetype = 'Digital-Single-BareModule'
+                    typeinfo = 'Digital-Single-BareModule'
                 elif name.find( '20UPGBQ' ) == 0:
-                    fetype = 'Digital-Quad-BareModule'
+                    typeinfo = 'Digital-Quad-BareModule'
 
                 cps.append(
                     {"_id": cpr_id,
@@ -188,8 +359,7 @@ def show_comps():
                      "name_orig": name,
                      "grade": {},
                      "hex" : hexName if name.find('20UPGFC')==0 else '',
-                     "fetype" : fetype,
-                     "wafer" : wafer
+                     "typeinfo" : typeinfo+wafer
                     }
                 )
                 
@@ -711,10 +881,10 @@ def query_docs(Keywords, Match):
             # Here also inside the viewer.query so I need to update this
             entries = userdb.viewer.query.find({"$and": query_list})
 
-    entries = sorted(entries, key=lambda x: x["timeStamp"], reverse=True)
+    components = sorted(entries, key=lambda x: x["timeStamp"], reverse=True)
 
-    for entry in entries:
-        run_ids.append(entry["runId"])
+    for component in components:
+        run_ids.append(component["runId"])
 
     return run_ids
 
diff --git a/viewer/templates/500.html b/viewer/templates/500.html
index 3f9a1358..7b40d371 100644
--- a/viewer/templates/500.html
+++ b/viewer/templates/500.html
@@ -9,16 +9,20 @@
         </h1>
 
         <h3 style="padding-left:30px;">
-          LocalDB scripts are currently unable to handle this request. <br>
-          Please check the error message below, and contact the developpers &raquo; <a href="https://mattermost.web.cern.ch/itkpixel/channels/local-database" target="_blank"><button type="button" class="btn btn-outline-dark">Mattermost</button></a></p><br>
-        </h3>
-
+          LocalDB scripts are currently unable to handle this request.
+	</h3>
+	
+        <ul>
+	  <li>Please check the error message below, and contact the developpers</li>
+	  <li>Please report which LocalDB viewer version is deployed on your site.</li>
+	</ul>
         <div style="text-align: left; padding-left:3%; padding-right: 3%;">
             <p style="background-color: #e6e6fa;  white-space: pre-line; padding-left: 2%; padding-right: 2%;">
                 <font size="4" color="ff0000">Error message:</font>
                 <font size="2" color="ff0000">{{ message }}</font>
             </p>
         </div>
+	<p> &raquo; <a href="https://mattermost.web.cern.ch/itkpixel/channels/local-database" target="_blank"><button type="button" class="btn btn-outline-dark">Mattermost</button></a></p>
      </div>
   </div>
 </div>
diff --git a/viewer/templates/components_table.html b/viewer/templates/components_table.html
index 0829ea6b..46f5a87d 100644
--- a/viewer/templates/components_table.html
+++ b/viewer/templates/components_table.html
@@ -58,16 +58,24 @@
 
 	{% set pagingInfo = table_docs['pagingInfo'] %}
 	
-	{% if table_docs['view'] == 'module' %}
-	<h3>Modules <span style="font-size: 50%;">Found {{ pagingInfo['entries'] }} modules in total</span></h3>
+	<h3>{{ table_docs['view'].upper() }} <span style="font-size: 50%;">Found {{ pagingInfo['entries'] }} components in total</span></h3>
 	
+        <form class="form-holizontal" role="form" method="post" action="{{ table_docs['page'] }}" accept-charset="UTF-8">
 	<div class="row align-items-top card-body" style="margin-top:0; padding-top:0; padding-bottom:0;">
-
+          <button type="submit" class="btn btn-secondary" style="padding-top: 0.05%; padding-bottom: 0.05%; font-size:90%;">Show All</button>
           <table class='table table-sm table-hover table-bordered' style='font-size: 10pt; margin-top:0;'>
           <thead class="table table-sm table-hover table-bordered">
             <tr>
-              <th style="text-align:left;">Module</th>
-              <th style="word-wrap:break-word; text-align:left;">Sub-Components</th>
+              <th style="word-wrap:break-word; text-align:center;">
+		  <div class="balloonoya">
+                    <button class="btn btn-secondary" style="padding-top:0; padding-bottom:0; font-size: 90%;" id="archive">Archive</button>
+                    <!-- span class="balloon">
+                      Click the checkbox and press this button to hide the module from the list.
+                    </span-->
+		  </div>
+              </th>
+              <th style="text-align:left;">{{ table_docs['view'].upper() }}</th>
+              <th style="word-wrap:break-word; text-align:left;">Relational Components</th>
               <th style="word-wrap:break-word; text-align:left;">Current Stage</th>
               <th style="word-wrap:break-word; text-align:left;">Last QC Test Type</th>
               <th style="word-wrap:break-word; text-align:left;">Date</th>
@@ -87,92 +95,64 @@
 	  </thead>
 
           <tbody align="left">
-            {% for module in table_docs['components']['modules'] %}
-	    {% set index = table_docs['components']['modules'].index( module ) %}
+            {% for component in table_docs['components'] %}
+	    {% set index = table_docs['components'].index( component ) %}
               <tr>
+		<td style="text-align:center;"><input type="checkbox" id="check_{{ component['name'] }}" value="false"></td>
                 <td style="word-wrap:break-word; text-align:left;">
-		  {% if module['name'] != '' %}
-                  <a href='{{ url_for('component_api.show_component', id=module['_id'], collection=module['collection']) }}'>{{ module['name'] }}</a>
-		  {% if module['name'].find( '20U' ) != 0 %}
+		  {% if component['name_delim'] != '' %}
+                  <a href='{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection']) }}'>{{ component['name'] }}</a>
+		  {% if component['name'].find( '20U' ) != 0 %}
 		  <strong style="color: red;"><br />Not ATLAS SN!</strong>
 		  {% else %}
 
-		  {# Module SN digestion #}
-		  <span style='color: #ccc;'>
-		  {% if 'PI' in module['name'] %}
-		  <br />L0/L1 Inner Module
-		  {% elif 'PB' in module['name'] %}
-		  <br />Outer Barrel Module
-		  {% elif 'PE' in module['name'] %}
-		  <br />Outer Endcap Module
-		  {% elif 'PGM2' in module['name'] %}
-		  <br />Outer Quad Module
-		  {% elif 'PGR2' in module['name'] %}
-		  <br />Dual Chip Module
-		  {% elif 'PGR-' in module['name'] %}
-		  <br />Single Chip Module
-		  {% elif 'XM' in module['name'] %}
-		  <br />Tutorial Module
-		  {% else %}
-		  <br />Others
-		  {% endif %}
-		  
-		  {% if   '0' == module['name'][9] %}
-		  / RD53A
-		  {% elif '1' == module['name'][9] %}
-		  / ITkPix_v1.0
-		  {% elif '2' == module['name'][9] %}
-		  / ITkPix_v1.1
-		  {% elif '3' == module['name'][9] %}
-		  / ITkPix_v2
-		  {% endif %}
-		  
-		  </span>
+		  {# Component SN digestion #}
+		  <br /><span style='color: #ccc;'>{{ component['typeinfo'] }}</span>
 		  
 		  {% endif %}
 		  {% else %}
-                  <a href='{{ url_for('component_api.show_component', id=module['_id'], collection=module['collection']) }}'><strong style="color: red;">Missing Module Name!</strong></a>
+                  <a href='{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection']) }}'><strong style="color: red;">Missing Module Name!</strong></a>
 		  {% endif %}
                 </td>
                 <td style="word-wrap:break-word; text-align:left;">
-                {% for chip in module['cps'] %}
-                <a href='{{ url_for('component_api.show_component', id=chip['_id'], collection=chip['collection']) }}' >{{ chip['name'] }}</a>
-		&nbsp;<span style="color:#ccc;">{{ chip['fetype'] }}{{chip['wafer']}}</span>
-		{% if chip['hex'] != '' %}
+                {% for subcomponent in component['cps'] %}
+                <a href='{{ url_for('component_api.show_component', id=subcomponent['_id'], collection=subcomponent['collection']) }}' >{{ subcomponent['name'] }}</a>
+		&nbsp;<span style="color:#ccc;">{{ subcomponent['typeinfo'] }}</span>
+		{% if subcomponent['hex'] != '' %}
 		{% endif %}
 		<br />
                 {% endfor %}
                 </td>
-                <td style="word-wrap:break-word; text-align:left;">{{ module['stage'] }}</td>
+                <td style="word-wrap:break-word; text-align:left;">{{ component['stage'] }}</td>
                 <td style="word-wrap:break-word; text-align:left;">
-                  {% if module['runId'] %}
-		  <a href='{{ url_for('component_api.show_component', id=module['_id'], collection=module['collection'], runId=module['runId']) }}'>
-		    {{ module['testType'] }}
+                  {% if component['runId'] %}
+		  <a href='{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], runId=component['runId']) }}'>
+		    {{ component['testType'] }}
 		  </a>
                   {% else %}
-		  {{ module['testType'] }}
+		  {{ component['testType'] }}
                   {% endif %}
 		</td>
-                <!--td style="word-wrap:break-word; text-align:left;">{{ module['user'] }}</td>
-                <td style="word-wrap:break-word; text-align:left;">{{ module['site'] }}</td-->
-                <td style="word-wrap:break-word; text-align:left;">{{ module['datetime'] }}</td>
+                <!--td style="word-wrap:break-word; text-align:left;">{{ component['user'] }}</td>
+                <td style="word-wrap:break-word; text-align:left;">{{ component['site'] }}</td-->
+                <td style="word-wrap:break-word; text-align:left;">{{ component['datetime'] }}</td>
                 <!--td style="word-wrap:break-word; text-align:left;">
-                  {% if module['runId'] %}
-                  <a href='{{ url_for('component_api.show_component', id=module['_id'], collection=module['collection'], runId=module['runId']) }}'>result page</a>
+                  {% if component['runId'] %}
+                  <a href='{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], runId=component['runId']) }}'>result page</a>
                   {% endif %}
                 </td-->
                 <td style="word-wrap:break-word; text-align:left;">
                   {% if session['logged_in'] %}
-                    <form method="post" action="{{ url_for('tag_api.put_tag', componentid=module["_id"]) }}" style="margin-bottom: 0%;">
+                    <form method="post" action="{{ url_for('tag_api.put_tag', componentid=component["_id"]) }}" style="margin-bottom: 0%;">
                     <select id='tag_name' name='tag_name' onchange="this.form.submit();">
                     <option selected="selected" value="">Select a Tag</option>
-                    {% for tag in module['component_tag_candidate'] %}
+                    {% for tag in component['component_tag_candidate'] %}
                       <option value="{{tag['name']}}">{{ tag['name'] }}</option>
                     {% endfor %}
                     </select>
                     </form>
                   {% endif %}
-                  {% for tag in module['component_tag'] %}
+                  {% for tag in component['component_tag'] %}
                     <span class="badge badge-pill badge-primary"><i class="fa fa-tag"></i> {{ tag['name'] }}</span><br>
                   {% endfor %}
                 </td>
@@ -180,9 +160,8 @@
             {% endfor %}
           </tbody>
         </table>
-	{% else %}
-	<h3>Others <span style="font-size: 50%;">Found {{ pagingInfo['entries'] }} modules in total</span></h3>
-	{% endif %}
+	</form>
+	
 	</div>
 
         {% if pagingInfo["minPage"] != pagingInfo["maxPage"] %}
diff --git a/viewer/templates/parts/nav.html b/viewer/templates/parts/nav.html
index 22982a35..2f4b4b68 100644
--- a/viewer/templates/parts/nav.html
+++ b/viewer/templates/parts/nav.html
@@ -16,11 +16,15 @@
     <div class="navbar-brand">
     <ul class="nav navbar-nav mr-auto">
     <b>
-      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/">TOP</a></li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/">Top</a></li>
       <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"> | </li>
-      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/components?view=module">MODULES</a></li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/components?view=module">Modules</a></li>
       <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"> | </li>
-      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/scan">SCANS</a></li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/components?view=module_pcb">PCBs</a></li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"> | </li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/components?view=bare_module">Bare Modules</a></li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"> | </li>
+      <li style="display: inline-block; margin-right: 2pt; font-size: 12pt;"><a href="/localdb/scan">Electrical Scans</a></li>
     </b>
     </ul>
     </div>
diff --git a/viewer/templates/scan_table.html b/viewer/templates/scan_table.html
index 0c664ef9..2f6d3585 100644
--- a/viewer/templates/scan_table.html
+++ b/viewer/templates/scan_table.html
@@ -93,7 +93,7 @@
               <th scope="col" colspan=1 rowspan=1 style="word-wrap:break-word; text-align:left;">
                 <div class="balloonoya">Tag <i class="fa fa-question-circle "></i>:
                   <form action="{{ url_for('tag_api.create_tag') }}" style="display: inline-block; margin: 0%;">
-                    <button class="btn btn-outline-dark btn-sm" style="padding-top:0; padding-bottom:0; font-size: 90%;">Creat</button>
+                    <button class="btn btn-outline-dark btn-sm" style="padding-top:0; padding-bottom:0; font-size: 90%;">Create</button>
                   </form>
                   <span class="balloon">
                     Create tag with the Link. <br>
diff --git a/viewer/templates/toppage.html b/viewer/templates/toppage.html
index 7fd052ba..b8a74d8c 100644
--- a/viewer/templates/toppage.html
+++ b/viewer/templates/toppage.html
@@ -43,6 +43,7 @@ table.toppage td.border_inner {
       {% if table_docs['page'] == 'components' or table_docs['page']=='scan' %}
         <form class="form-holizontal" role="form" method="get" action="{{ table_docs['page'] }}" accept-charset="UTF-8">
           <h5>
+          <input type="hidden" name="view" value="{{ table_docs['view'] }}" placeholder="View">
           <input type="search" name="keywords" value="{{ table_docs['keywords'] }}" placeholder="Input keywords">
           {% if table_docs['match'] == 'perfect' %}
             <input type="radio" name="match" value="partial"> Partial match
@@ -82,8 +83,10 @@ table.toppage td.border_inner {
   <div class="row align-items-center justify-content-center">
     <div class="col">
       <h2>Browse LocalDB</h2>
-      <h4>&nbsp;<a href="{{ url_for('toppage_api.show_comps')}}"><i class="fa fa-desktop "></i> Browse Components</a></h4>
-      <h4>&nbsp;<a href="{{ url_for('toppage_api.show_scans')}}"><i class="fa fa-desktop "></i> Browse Scans</a></h4>
+      <h4>&nbsp;<a href="{{ url_for('toppage_api.show_comps', view='module') }}"><i class="fa fa-desktop "></i> Browse Modules</a></h4>
+      <h4>&nbsp;<a href="{{ url_for('toppage_api.show_comps', view='module_pcb') }}"><i class="fa fa-desktop "></i> Browse PCBs</a></h4>
+      <h4>&nbsp;<a href="{{ url_for('toppage_api.show_comps', view='bare_module') }}"><i class="fa fa-desktop "></i> Browse Bare Modules</a></h4>
+      <h4>&nbsp;<a href="{{ url_for('toppage_api.show_scans')}}"><i class="fa fa-desktop "></i> Browse Electrical Scans</a></h4>
       {% if session['logged_in'] %}
       <br>
         <h2>Customize LocalDB</h2>
-- 
GitLab


From 2fd5ce64bad4849fa22fde896ea8549ef08fdc6c Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Wed, 20 Jul 2022 22:46:18 +0900
Subject: [PATCH 2/7] supporting archive feature using tags

---
 viewer/pages/toppage.py                | 348 +++++--------------------
 viewer/templates/components_table.html |  24 +-
 2 files changed, 85 insertions(+), 287 deletions(-)

diff --git a/viewer/pages/toppage.py b/viewer/pages/toppage.py
index d211b3bb..8af527da 100755
--- a/viewer/pages/toppage.py
+++ b/viewer/pages/toppage.py
@@ -66,14 +66,6 @@ def show_comps():
 
     table_docs = {"components": [] }
 
-    # get keywords
-    if not request.form.get("keywords") == None:
-        table_docs["keywords"] = request.form.get("keywords", "")
-        table_docs["match"] = request.form.get("match", "None")
-    else:
-        table_docs["keywords"] = request.args.get("keywords", "")
-        table_docs["match"] = request.args.get("match", "None")
-        
     table_docs['view'] = request.args.get("view", None)
     
     if table_docs['view'] == None:
@@ -82,9 +74,50 @@ def show_comps():
     view = table_docs['view']
     
     logger.debug('show_comps(): view = {}'.format( view ) )
+    
+    
+    # Action modes
+    archive_list = []
+    doArchive = False
+    if request.form.get("archive"):
+        logger.debug('show_comps(): archive = {}'.format( request.form.get("archive") ) )
+        doArchive = True
+        
+        for key in request.form.keys():
+            flag = request.form.get( key )
+            if flag:
+                archive_list.append( key[key.find('_')+1:] )
+        
+    doShowAll = False
+    if request.form.get("showall"):
+        logger.debug('show_comps(): showall = {}'.format( request.form.get("archive") ) )
+        doShowAll = True
 
+        
+    # get keywords
+    if request.form.get("keywords"):
+        table_docs["keywords"] = request.form.get("keywords", "")
+        table_docs["match"] = request.form.get("match", "None")
+    else:
+        table_docs["keywords"] = request.args.get("keywords", "")
+        table_docs["match"] = request.args.get("match", "None")
+    
+    if table_docs["keywords"] != "":
+        doShowAll = True
+        
     compsPerPage = 10
     
+    thistime = datetime.utcnow()
+    
+    if not userdb.viewer.tag.categories.find_one( { "name":"archived" } ):
+        userdb.viewer.tag.categories.insert_one(
+            {
+                "sys": {"rev": 0, "cts": thistime, "mts": thistime},
+                "name": "archived",
+                "user_id": None
+            }
+        )
+    
     page = 1
     if not request.args.get("p", 1) == "":
         page = int(request.args.get("p", 1))
@@ -94,10 +127,30 @@ def show_comps():
     for component in components:
         
         # logger.info( 'component: {}'.format( component ) )
-        
         cmp_id = str(component["_id"])
         
-        cmp_ids.append( cmp_id )
+        ### tags
+        tag_candidates = [ c for c in userdb.viewer.tag.categories.find( {} ) ]
+        
+        ### put tags
+        tags = [ t for t in userdb.viewer.tag.docs.find( {"componentid": cmp_id} ) ]
+        
+        isArchived = False
+        for tag in tags:
+            if tag['name'] == "archived":
+                isArchived = True
+                
+        if (not isArchived) and component['name'] in archive_list:
+            tagsdocs = {
+                "sys": {"rev": 0, "cts": thistime, "mts": thistime},
+                "name": "archived",
+                "componentid" : cmp_id
+            }
+            userdb.viewer.tag.docs.insert_one( tagsdocs )
+            isArchived = True
+        
+        if not isArchived:
+            cmp_ids.append( cmp_id )
         
         
         cps = []
@@ -157,19 +210,6 @@ def show_comps():
         
         result = localdb.QC.result.find_one( {"component": cmp_id} )
 
-        ### tags
-        query = {}
-        module_tag_candidates = userdb.viewer.tag.categories.find(query)
-        tag_candidate = []
-        for module_tag in module_tag_candidates:
-            tag_candidate.append(module_tag)
-        ### put tags
-        query = {"componentid": cmp_id}
-        module_tags = userdb.viewer.tag.docs.find(query)
-        tag = []
-        for module_tag in module_tags:
-            tag.append(module_tag)
-        
         component_data = {
             "_id": cmp_id,
             "collection": "component",
@@ -179,8 +219,8 @@ def show_comps():
             "cps": cps,
             "grade": {},
             "proDB": component.get("proDB", False),
-            "component_tag_candidate": tag_candidate,
-            "component_tag": tag,
+            "component_tag_candidate": tag_candidates,
+            "component_tag": tags,
         }
         
         if qcStatus:
@@ -214,8 +254,13 @@ def show_comps():
             table_docs["keywords"], search_targets, table_docs["match"]
         )
         
+        logger.info( '{} {}'.format( component_data['name'], component_data["component_tag"] ) )
         if isKeywordMatched:
-            table_docs["components"].append( component_data )
+            if doShowAll:
+                table_docs["components"].append( component_data )
+            else:
+                if not isArchived:
+                    table_docs["components"].append( component_data )
         
         
     #end for component in components:
@@ -239,262 +284,13 @@ def show_comps():
     
     table_docs.update( { 'pagingInfo':pagingInfo } )
     table_docs["page"] = "components"
-    table_docs["title"] = "Component List"
+    table_docs["title"] = "{} List".format( view.upper() )
     table_docs["download_module"] = os.path.exists(IF_DIR+"/doing_download.txt")
     
     return render_template(
         "toppage.html", table_docs=table_docs, timezones=pytz.all_timezones
     )
 
-    #######----------------------------------------------------------------------------------------------
-
-    # Filter modules
-    index = 0
-    for cmp_id in cmp_ids:
-        query = {"_id": ObjectId(cmp_id)}
-        this_cmp = localdb.component.find_one(query)
-
-        if this_cmp.get("componentType", "front-end_chip").lower() == "module":
-            key = "modules"
-            id_key = "child"
-            query = {"parent": cmp_id}
-        else:
-            continue
-        
-        index += 1
-
-        ### cpr entries
-        components = localdb.childParentRelation.find(query)
-        cpr_ids = []
-        for component in components:
-            cpr_ids.append(component[id_key])
-        cps = []
-        for cpr_id in cpr_ids:
-            query = {"_id": ObjectId(cpr_id)}
-            this_cp = localdb.component.find_one(query)
-            if this_cp:
-                try:
-                    name = this_cp["name"]
-                except:
-                    name = this_cp["serialNumber"]
-
-                hexName = ''
-                if name.find('20U') == 0:
-                    try:
-                        hexName  = "{0:#0{1}x}".format(int( name[-7:] ),7)
-                    except:
-                        pass
-
-                batchMap = { '0':'RD53A', '1':'ITkPix' }
-                
-                typeinfo = 'Undef'
-                try:
-                    typeinfo = batchMap[hexName[2]]
-                except:
-                    pass
-                    
-                if 'PI' in name:
-                    typeinfo = "L0/L1 Inner Module"
-                elif 'PB' in name:
-                    typeinfo = "Outer Barrel Module"
-                elif 'PE' in name:
-                    typeinfo = "Outer Endcap Module"
-                elif 'PGM2' in name:
-                    typeinfo = "Outer Quad Module"
-                elif 'PGR2' in name:
-                    typeinfo = "Dual Chip Module"
-                elif 'PGR-' in name:
-                    typeinfo = "Single Chip Module"
-                elif 'XM' in name:
-                    typeinfo = "Tutorial Module"
-                else:
-                    typeinfo = "Others"
-                    
-                    
-                if   '0' == name[7]:
-                    typeinfo+= ' / RD53A'
-                elif '1' == name[7]:
-                    typeinfo+=' / ITkPix_v1.0'
-                elif '2' == name[7]:
-                    typeinfo+=' / ITkPix_v1.1'
-                elif '3' == name[7]:
-                    typeinfo+=' / ITkPix_v2'
-                    
-                    
-                wafer=''
-                if name.find('20UPGFC') == 0:
-                    wafer= '-{}-({},{})'.format( hexName[3:4], hexName[5], hexName[6] )
-                    
-                if name.find( '20UPGXF' ) == 0:
-                    typeinfo = 'Tutorial-FE'
-                elif name.find( '20UPGXB' ) == 0:
-                    typeinfo = 'Tutorial-BareModule'
-                elif name.find( '20UPGXP' ) == 0:
-                    typeinfo = 'Tutorial-PCB'
-                elif name.find( '20UPGPQ' ) == 0:
-                    typeinfo = 'QuadPCB'
-                elif name.find( '20UPGPD' ) == 0:
-                    typeinfo = 'DualPCB'
-                elif name.find( '20UPIPT' ) == 0:
-                    typeinfo = 'TripletL0StavePCB'
-                elif name.find( '20UPIP0' ) == 0:
-                    typeinfo = 'TripletL0R0PCB'
-                elif name.find( '20UPIP5' ) == 0:
-                    typeinfo = 'TripletL0R0.5PCB'
-                elif name.find( '20UPGB1' ) == 0:
-                    typeinfo = 'Single-BareModule'
-                elif name.find( '20UPGB2' ) == 0:
-                    typeinfo = 'Dual-BareModule'
-                elif name.find( '20UPGB4' ) == 0:
-                    typeinfo = 'Quad-BareModule'
-                elif name.find( '20UPGBS' ) == 0:
-                    typeinfo = 'Digital-Single-BareModule'
-                elif name.find( '20UPGBQ' ) == 0:
-                    typeinfo = 'Digital-Quad-BareModule'
-
-                cps.append(
-                    {"_id": cpr_id,
-                     "collection": "component",
-                     "name": name[0:3]+' '+name[3:7]+' '+name[7:9]+' '+name[9:] if name.find('20U') == 0 else name,
-                     "name_orig": name,
-                     "grade": {},
-                     "hex" : hexName if name.find('20UPGFC')==0 else '',
-                     "typeinfo" : typeinfo+wafer
-                    }
-                )
-                
-        ### Latest Scan
-        query = {"component": cmp_id}
-        run_entries = (
-            localdb.QC.result.find(query).sort([("$natural", -1)]).limit(1)
-        )
-        result = {
-            "stage": None,
-            "runId": None,
-            "datetime": None,
-            "testType": None,
-            "user": None,
-            "site": None,
-        }
-        for this_run in run_entries:
-            result.update(
-                {
-                    "stage": this_run["currentStage"],
-                    "runId": str(this_run["_id"]),
-                    "datetime": setTime(
-                        this_run["sys"]["cts"],
-                        session.get("timezone", str(get_localzone())),
-                    ),
-                    "testType": this_run["testType"],
-                    "user": this_run["user"],
-                    "site": this_run["address"],
-                }
-            )
-
-        ### tags
-        query = {}
-        module_tag_candidates = userdb.viewer.tag.categories.find(query)
-        tag_candidate = []
-        for module_tag in module_tag_candidates:
-            tag_candidate.append(module_tag)
-        ### put tags
-        query = {"componentid": cmp_id}
-        module_tags = userdb.viewer.tag.docs.find(query)
-        tag = []
-        for module_tag in module_tags:
-            tag.append(module_tag)
-
-        try:
-            name = this_cmp["name"]
-        except:
-            name = this_cmp["serialNumber"]
-        module_data = {
-            "_id": cmp_id,
-            "collection": "component",
-            "name": name[0:3]+' '+name[3:7]+' '+name[7:9]+' '+name[9:] if name.find('20U') == 0 else name,
-            "cps": cps,
-            "grade": {},
-            "stage": result["stage"],
-            "runId": result["runId"],
-            "datetime": result["datetime"],
-            "testType": result["testType"],
-            "user": result["user"],
-            "site": result["site"],
-            "proDB": this_cmp.get("proDB", False),
-            "component_tag_candidate": tag_candidate,
-            "component_tag": tag,
-        }
-
-        query_targets = []
-        query_targets.append(name)
-        query_targets.append(module_data["name"])
-        query_targets.append(module_data["stage"])
-        query_targets.append(module_data["user"])
-        query_targets.append(module_data["site"])
-        query_targets.append(module_data["datetime"])
-        for tag in module_data["component_tag"]:
-            query_targets.append(tag["name"])
-        for child in module_data["cps"]:
-            query_targets.append(child["name"])
-            query_targets.append(child["name_orig"])
-            
-        isKeywordMatched = query_keywords(
-            table_docs["keywords"], query_targets, table_docs["match"]
-        )
-        
-        if isKeywordMatched:
-            table_docs["components"][key].append( module_data )
-        
-
-    table_docs["components"].update(
-        {"module_num": len(table_docs["components"]["modules"])}
-    )
-    
-    for m in table_docs["components"]["modules"]:
-        if m["datetime"] == None:
-            m["datetime"] = ''
-                
-    modules = sorted(
-        table_docs["components"]["modules"],
-        key=lambda x: x["datetime"],
-        reverse=True,
-    )
-    table_docs["components"]["modules"] = modules[pageMinIndex:pageMaxIndex]
-
-    nModulesTotal = len( modules )
-    maxPage = len(modules) // compsPerPage + 1
-    minRange = max(1, page - 2)
-    maxRange = min(maxPage, minRange+3)
-    pageRange = list( range( minRange, maxRange+1 ) )
-
-    pagingInfo = {
-        "thisPage": page,
-        "range" : pageRange,
-        "minPage": 1,
-        "maxPage": maxPage,
-        "entries" : nModulesTotal
-    }
-    table_docs.update( { 'pagingInfo':pagingInfo } )
-    
-    
-    table_docs["components"].update(
-        {"chip_num": len(table_docs["components"]["chips"])}
-    )
-    chips = sorted(
-        table_docs["components"]["chips"],
-        key=lambda x: x["name"],
-        reverse=True,
-    )
-    table_docs["components"]["chips"] = chips
-    
-    table_docs["page"] = "components"
-    table_docs["title"] = "Component List"
-    table_docs["download_module"] = os.path.exists(IF_DIR+"/doing_download.txt")
-
-    return render_template(
-        "toppage.html", table_docs=table_docs, timezones=pytz.all_timezones
-    )
-
 
 ####################
 # Show test run list
diff --git a/viewer/templates/components_table.html b/viewer/templates/components_table.html
index 46f5a87d..ceacc45f 100644
--- a/viewer/templates/components_table.html
+++ b/viewer/templates/components_table.html
@@ -58,21 +58,21 @@
 
 	{% set pagingInfo = table_docs['pagingInfo'] %}
 	
-	<h3>{{ table_docs['view'].upper() }} <span style="font-size: 50%;">Found {{ pagingInfo['entries'] }} components in total</span></h3>
-	
         <form class="form-holizontal" role="form" method="post" action="{{ table_docs['page'] }}" accept-charset="UTF-8">
+          <input type="hidden" name="view" value="{{ table_docs['view'] }}" placeholder="View">
+	  
+	<h3><span style="font-size: 50%;">Found {{ pagingInfo['entries'] }} {{ table_docs['view'].upper() }} components in LocalDB.
+	  <button class="btn btn-info" style="padding-top: 0; padding-bottom: 0; font-size:90%; margin-bottom: 5pt;" name="showall" value="true">Show All</button>
+	  </span> 
+	</h3>
+	
 	<div class="row align-items-top card-body" style="margin-top:0; padding-top:0; padding-bottom:0;">
-          <button type="submit" class="btn btn-secondary" style="padding-top: 0.05%; padding-bottom: 0.05%; font-size:90%;">Show All</button>
           <table class='table table-sm table-hover table-bordered' style='font-size: 10pt; margin-top:0;'>
           <thead class="table table-sm table-hover table-bordered">
             <tr>
               <th style="word-wrap:break-word; text-align:center;">
-		  <div class="balloonoya">
-                    <button class="btn btn-secondary" style="padding-top:0; padding-bottom:0; font-size: 90%;" id="archive">Archive</button>
-                    <!-- span class="balloon">
-                      Click the checkbox and press this button to hide the module from the list.
-                    </span-->
-		  </div>
+		<input type="hidden" name="view" value="{{ table_docs['view'] }}" placeholder="View">
+                <button class="btn btn-info" style="padding-top:0; padding-bottom:0; font-size: 90%;" name="archive" value="true">Archive</button>
               </th>
               <th style="text-align:left;">{{ table_docs['view'].upper() }}</th>
               <th style="word-wrap:break-word; text-align:left;">Relational Components</th>
@@ -82,7 +82,7 @@
               <th style="word-wrap:break-word; text-align:left;"><div class="balloonoya">Tag <i class="fa fa-question-circle "></i>:
 		  <div class="balloonoya">
                     <form action="{{ url_for('tag_api.create_tag') }}" style="display: inline-block; margin: 0%;">
-                      <button class="btn btn-outline-dark btn-sm" style="padding-top:0; padding-bottom:0; font-size: 90%;">Create New</button>
+                      <button class="btn btn-info btn-sm" style="padding-top:0; padding-bottom:0; font-size: 90%;">Create</button>
                     </form>
                     <span class="balloon">
                       Create tags with the button. <br>
@@ -98,7 +98,9 @@
             {% for component in table_docs['components'] %}
 	    {% set index = table_docs['components'].index( component ) %}
               <tr>
-		<td style="text-align:center;"><input type="checkbox" id="check_{{ component['name'] }}" value="false"></td>
+		<td style="text-align:center;">
+		    <input class="form-check-input" type="checkbox" name="archive_{{ component['name_orig'] }}" value="false">
+		</td>
                 <td style="word-wrap:break-word; text-align:left;">
 		  {% if component['name_delim'] != '' %}
                   <a href='{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection']) }}'>{{ component['name'] }}</a>
-- 
GitLab


From a836d05043a7d6a0eb77f638684770f5a54a12eb Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Fri, 22 Jul 2022 14:38:24 +0900
Subject: [PATCH 3/7] archive ans showall features to electrical scans

---
 viewer/pages/tag.py                    | 15 +++--
 viewer/pages/toppage.py                | 65 +++++++++++++++++++++-
 viewer/templates/components_table.html |  2 +-
 viewer/templates/scan_table.html       | 76 ++++++++++++++------------
 4 files changed, 111 insertions(+), 47 deletions(-)

diff --git a/viewer/pages/tag.py b/viewer/pages/tag.py
index a0346ce2..80c29927 100755
--- a/viewer/pages/tag.py
+++ b/viewer/pages/tag.py
@@ -46,8 +46,7 @@ def create_tag():
             userdb.viewer.tag.categories.insert_one(
                 {
                     "sys": {"rev": 0, "cts": thistime, "mts": thistime},
-                    "name": taginfo[0],
-                    "user_id": session["user_id"],
+                    "name": taginfo[0]
                 }
             )
 
@@ -76,8 +75,7 @@ def put_tag():
     tag_name = request.form.get("tag_name")
     tagdocs = {
         "sys": {"rev": 0, "cts": thistime, "mts": thistime},
-        "name": tag_name,
-        "user_id": session["user_id"],
+        "name": tag_name
     }
     componentid = request.args.get("componentid", -1)
     runId = request.args.get("runId", -1)
@@ -109,10 +107,11 @@ def put_tag():
             userdb.viewer.tag.docs.insert(tagdocs)
         else:
             query_doc = userdb.viewer.query.find_one({"runId": runId})
-            new_list = query_doc["data"]
-            new_list.remove(str(tag_name))
-            userdb.viewer.query.update({"runId": runId}, {"$set": {"data": new_list}})
-            userdb.viewer.tag.docs.remove(query)
+            if query_doc:
+                new_list = query_doc["data"]
+                new_list.remove(str(tag_name))
+                userdb.viewer.query.update({"runId": runId}, {"$set": {"data": new_list}})
+                userdb.viewer.tag.docs.remove(query)
 
     return redirect(request.headers.get("Referer"))
 
diff --git a/viewer/pages/toppage.py b/viewer/pages/toppage.py
index 8af527da..1fb2740b 100755
--- a/viewer/pages/toppage.py
+++ b/viewer/pages/toppage.py
@@ -306,6 +306,25 @@ def show_scans():
         sort_cnt = int(request.args.get("p", 0))
 
     table_docs = {"run": []}
+    
+    # Action modes
+    archive_list = []
+    doArchive = False
+    if request.form.get("archive"):
+        logger.debug('show_comps(): archive = {}'.format( request.form.get("archive") ) )
+        doArchive = True
+        
+        for key in request.form.keys():
+            flag = request.form.get( key )
+            if flag:
+                archive_list.append( key[key.find('_')+1:] )
+        
+    doShowAll = False
+    if request.form.get("showall"):
+        logger.debug('show_comps(): showall = {}'.format( request.form.get("archive") ) )
+        doShowAll = True
+
+        
     # get keywords
     if not request.form.get("keywords") == None:
         table_docs["keywords"] = request.form.get("keywords", "")
@@ -313,6 +332,9 @@ def show_scans():
     else:
         table_docs["keywords"] = request.args.get("keywords", "")
         table_docs["match"] = request.args.get("match", "None")
+        
+    if table_docs["keywords"] != "":
+        doShowAll = True
 
     print(table_docs["keywords"])
     run_ids = query_docs(Keywords=table_docs["keywords"], Match=table_docs["match"])
@@ -331,14 +353,51 @@ def show_scans():
             run_num_list.append(sort_cnt * (max_num) + i)
 
 
+    thistime = datetime.utcnow()
+    
+    if not userdb.viewer.tag.categories.find_one( { "name":"archived" } ):
+        userdb.viewer.tag.categories.insert_one(
+            {
+                "sys": {"rev": 0, "cts": thistime, "mts": thistime},
+                "name": "archived",
+                "user_id": None
+            }
+        )
+    
     run_counts = 0
     if not nrun_entries == 0:
         for i in run_num_list:
             try:
                 run_data = getScanSummary(run_ids[i])
-                run_counts += 1
-                table_docs["run"].append({"run_data": run_data, "nrun": run_counts})
-            except:
+                
+                
+                isArchived = False
+                tags = run_data['testRun_tag']
+                for tag in tags:
+                    if tag['name'] == 'archived':
+                        isArchived = True
+                        break
+                
+                if (not isArchived) and str( run_data['_id'] ) in archive_list:
+                    tagsdocs = {
+                        "sys": {"rev": 0, "cts": thistime, "mts": thistime},
+                        "name": "archived",
+                        "runId" : str( run_data['_id'] )
+                    }
+                    userdb.viewer.tag.docs.insert_one( tagsdocs )
+                    userdb.viewer.query.update( {"runId": str( run_data['_id'] ) }, {"$push": {"data": tagsdocs['name'] } } )
+                    isArchived = True
+        
+                if doShowAll:
+                    table_docs["run"].append( {"run_data": run_data, "nrun": run_counts} )
+                    run_counts += 1
+                
+                else:
+                    if not isArchived:
+                        table_docs["run"].append( {"run_data": run_data, "nrun": run_counts} )
+                        run_counts += 1
+            except Exception as e:
+                logger.warning( '{}'.format(e) )
                 pass
 
     table_docs["run"] = sorted(
diff --git a/viewer/templates/components_table.html b/viewer/templates/components_table.html
index ceacc45f..8ba32126 100644
--- a/viewer/templates/components_table.html
+++ b/viewer/templates/components_table.html
@@ -99,7 +99,7 @@
 	    {% set index = table_docs['components'].index( component ) %}
               <tr>
 		<td style="text-align:center;">
-		    <input class="form-check-input" type="checkbox" name="archive_{{ component['name_orig'] }}" value="false">
+		  <input class="form-check-input" type="checkbox" name="archive_{{ component['name_orig'] }}" style="-moz-transform:scale(1.4); -webkit-transform:scale(1.4); transform:scale(1.4);" value="false">
 		</td>
                 <td style="word-wrap:break-word; text-align:left;">
 		  {% if component['name_delim'] != '' %}
diff --git a/viewer/templates/scan_table.html b/viewer/templates/scan_table.html
index 2f6d3585..1ce35404 100644
--- a/viewer/templates/scan_table.html
+++ b/viewer/templates/scan_table.html
@@ -52,32 +52,21 @@
   <div class="row align-items-left justify-content-left">
     <div class="col">
 
+      <form class="form-holizontal" role="form" method="post" action="{{ table_docs['page'] }}" accept-charset="UTF-8">
+        <input type="hidden" name="view" value="" placeholder="View">
+	
+	<h3><span style="font-size: 50%;">Found {{ table_docs["run"]|length }} scans in LocalDB.
+	    <button class="btn btn-info" style="padding-top: 0; padding-bottom: 0; font-size:90%; margin-bottom: 5pt;" name="showall" value="true">Show All</button>
+	  </span> 
+	</h3>
+	
       <table class="table table-sm toppage" style="font-size: 11pt;">
-        <div style="text-align: center; font-size: 14px;">
-          <ul class="page-list">
-            {% if table_docs['now_cnt']!=0 %}
-            <li style="display: inline;">
-              <a href="{{ url_for('toppage_api.show_scans', p=0, keywords=table_docs['keywords'], match=table_docs['match']) }}">&#8810;</a>
-            </li>
-            {% endif %}
-            {% for i in table_docs['cnt'] %}
-             {% if i==table_docs['now_cnt'] %}
-              <li style="display: inline-flex; justify-content: center; align-items: center; flex-flow: column; vertical-align: top; inline; height: 20px; width: 20px; border-radius: 50%; line-height: 20px; background: #FFEEAA; text-align: center; font-size: 14pt">
-              {% else %}
-              <li style="display: inline;">
-              {% endif %}
-	              <a href="{{ url_for('toppage_api.show_scans', p=i,keywords=table_docs['keywords'], match=table_docs['match']) }}">{{i+1}}</a>
-              </li>
-            {% endfor %}
-            {% if table_docs['now_cnt']!=table_docs['max_cnt'] %}
-            <li style="display: inline;">
-              <a href="{{ url_for('toppage_api.show_scans', p=table_docs['max_cnt'],keywords=table_docs['keywords'], match=table_docs['match']) }}">&#8811;</a>
-            </li>
-            {% endif %}
-          </ul>
-        </div>
         <thead class="table-light">
           <tr>
+              <th scope="col" rowspan=2 style="word-wrap:break-word; text-align:center;">
+		<input type="hidden" name="view" value="" placeholder="View">
+                <button class="btn btn-info" style="padding-top:0; padding-bottom:0; font-size: 90%;" name="archive" value="true">Archive</button>
+              </th>
             <th scope="col" rowspan=2 style="word-wrap:break-word; text-align:left;">Module Name<br />(ATLAS SN)</th>
             <th scope="col" rowspan=2 style="word-wrap:break-word; text-align:left;">Chip Name<br />(ATLAS SN)</th>
             <th scope="col" colspan=5 style="word-wrap:break-word; text-align:left;">Test Data</th>
@@ -111,6 +100,9 @@
             {% else %}
             <tr style="background: #AABBCC;" name="test-table" disabled="disabled">
             {% endif %}
+		<td style="text-align:center;">
+		    <input class="form-check-input" type="checkbox" name="archive_{{ run_data['run_data']['_id'] }}" value="false">
+		</td>
                 <td style="word-wrap:break-word; text-align:left;">
                   {% for component in run_data['run_data']['components'] %}
                     {% if component['chip_id']=='module' %}
@@ -150,18 +142,6 @@
                 <td style="word-wrap:break-word; text-align:left;">{{ run_data['run_data']["site"] }}</td>
                 <td style="word-wrap:break-word; text-align:left;">{{ run_data['run_data']["datetime"] }}</td>
                 <td style="word-wrap:break-word; text-align:left;">{{ run_data['run_data']["setT"] }}</td>
-                <!--td style="word-wrap:break-word; text-align:left;">
-                  {% set hoge = [] %}
-                  {% for component in run_data['run_data']['components'] %}
-                  {% if component['chip_id']=='module' %}
-                  {% set _ = hoge.append(0)%}
-                  <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='electrical', runId=run_data['run_data']['_id']) }}">result page</a>
-                  {% endif %}
-                  {% endfor %}
-                  {% if not hoge %}
-                  result page</a>
-                  {% endif %}
-                </td-->
                 <td style="word-wrap:break-word; text-align:left; line-height: 1.5;">
                   {% if session['logged_in'] %}
                     <form method="post" action="{{ url_for('tag_api.put_tag', runId=run_data['run_data']['_id']) }}" style="margin-bottom: 0%;">
@@ -181,6 +161,8 @@
           {% endfor %}
         </tbody>
       </table>
+      
+      </form>
 
       <form action="">
       <p style="font-size: 8pt;" align="right">
@@ -189,6 +171,30 @@
       </p>
       </form>
 
+        <div style="text-align: center; font-size: 14px;">
+          <ul class="page-list">
+            {% if table_docs['now_cnt']!=0 %}
+            <li style="display: inline;">
+              <a href="{{ url_for('toppage_api.show_scans', p=0, keywords=table_docs['keywords'], match=table_docs['match']) }}">&#8810;</a>
+            </li>
+            {% endif %}
+            {% for i in table_docs['cnt'] %}
+             {% if i==table_docs['now_cnt'] %}
+              <li style="display: inline-flex; justify-content: center; align-items: center; flex-flow: column; vertical-align: top; inline; height: 20px; width: 20px; border-radius: 50%; line-height: 20px; background: #FFEEAA; text-align: center; font-size: 14pt">
+              {% else %}
+              <li style="display: inline;">
+              {% endif %}
+	              <a href="{{ url_for('toppage_api.show_scans', p=i,keywords=table_docs['keywords'], match=table_docs['match']) }}">{{i+1}}</a>
+              </li>
+            {% endfor %}
+            {% if table_docs['now_cnt']!=table_docs['max_cnt'] %}
+            <li style="display: inline;">
+              <a href="{{ url_for('toppage_api.show_scans', p=table_docs['max_cnt'],keywords=table_docs['keywords'], match=table_docs['match']) }}">&#8811;</a>
+            </li>
+            {% endif %}
+          </ul>
+        </div>
+	
     </div>
   </div>
 </div>
-- 
GitLab


From 6d2bef1022404dc8708126723802fbf1d5fd6709 Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Sun, 24 Jul 2022 16:48:35 +0900
Subject: [PATCH 4/7] supporting ITkDB testRun result transaction records,
 overlap removal and deletion of obsolete testRuns on ITkPD

---
 viewer/itkpd-interface/.auth                  |  Bin 13916 -> 0 bytes
 viewer/itkpd-interface/lib/PDInterface.py     |   12 +-
 .../itkpd-interface/lib/download_QC_info.py   |   31 +-
 viewer/itkpd-interface/lib/upload_results.py  | 1493 ++++++++++-------
 .../{ => displayResults}/SLDOVIresult.html    |    0
 .../{ => displayResults}/adc_calibration.html |    0
 .../{ => displayResults}/coplanarity.html     |    0
 .../{ => displayResults}/electrical.html      |    0
 .../glueattachresult.html                     |    0
 .../{ => displayResults}/irefresult.html      |    0
 .../{ => displayResults}/massresult.html      |    0
 .../{ => displayResults}/metresult.html       |    0
 .../{ => displayResults}/paryleneresult.html  |    0
 .../{ => displayResults}/pulltest.html        |    0
 .../{ => displayResults}/pullupresult.html    |    0
 .../{ => displayResults}/qc_others.html       |    0
 .../{ => displayResults}/sensorIVresult.html  |    0
 .../{ => displayResults}/thermalresult.html   |    0
 .../{ => displayResults}/tuning.html          |    0
 .../{ => displayResults}/viresult.html        |    0
 .../wirebondingresult.html                    |    0
 .../wpenvelope_result.html                    |    0
 .../{ => displayResults}/xrayresult.html      |    0
 viewer/templates/displayTests/massresult.html |  118 ++
 viewer/templates/displayTests/viresult.html   |  138 ++
 .../displayTests/wirebondingresult.html       |  148 ++
 .../displayTests/wpenvelope_result.html       |  111 ++
 viewer/templates/displayTests/xrayresult.html |  281 ++++
 .../templates/{ => electrical_test}/plot.html |    0
 .../{ => electrical_test}/result.html         |    0
 .../{ => electrical_test}/selection.html      |    0
 31 files changed, 1694 insertions(+), 638 deletions(-)
 delete mode 100644 viewer/itkpd-interface/.auth
 rename viewer/templates/{ => displayResults}/SLDOVIresult.html (100%)
 rename viewer/templates/{ => displayResults}/adc_calibration.html (100%)
 rename viewer/templates/{ => displayResults}/coplanarity.html (100%)
 rename viewer/templates/{ => displayResults}/electrical.html (100%)
 rename viewer/templates/{ => displayResults}/glueattachresult.html (100%)
 rename viewer/templates/{ => displayResults}/irefresult.html (100%)
 rename viewer/templates/{ => displayResults}/massresult.html (100%)
 rename viewer/templates/{ => displayResults}/metresult.html (100%)
 rename viewer/templates/{ => displayResults}/paryleneresult.html (100%)
 rename viewer/templates/{ => displayResults}/pulltest.html (100%)
 rename viewer/templates/{ => displayResults}/pullupresult.html (100%)
 rename viewer/templates/{ => displayResults}/qc_others.html (100%)
 rename viewer/templates/{ => displayResults}/sensorIVresult.html (100%)
 rename viewer/templates/{ => displayResults}/thermalresult.html (100%)
 rename viewer/templates/{ => displayResults}/tuning.html (100%)
 rename viewer/templates/{ => displayResults}/viresult.html (100%)
 rename viewer/templates/{ => displayResults}/wirebondingresult.html (100%)
 rename viewer/templates/{ => displayResults}/wpenvelope_result.html (100%)
 rename viewer/templates/{ => displayResults}/xrayresult.html (100%)
 create mode 100644 viewer/templates/displayTests/massresult.html
 create mode 100644 viewer/templates/displayTests/viresult.html
 create mode 100644 viewer/templates/displayTests/wirebondingresult.html
 create mode 100644 viewer/templates/displayTests/wpenvelope_result.html
 create mode 100644 viewer/templates/displayTests/xrayresult.html
 rename viewer/templates/{ => electrical_test}/plot.html (100%)
 rename viewer/templates/{ => electrical_test}/result.html (100%)
 rename viewer/templates/{ => electrical_test}/selection.html (100%)

diff --git a/viewer/itkpd-interface/.auth b/viewer/itkpd-interface/.auth
deleted file mode 100644
index f8914bfff254170aa357ae102d7efefc273edee8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 13916
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

diff --git a/viewer/itkpd-interface/lib/PDInterface.py b/viewer/itkpd-interface/lib/PDInterface.py
index 7a00e4fa..09f2d93d 100755
--- a/viewer/itkpd-interface/lib/PDInterface.py
+++ b/viewer/itkpd-interface/lib/PDInterface.py
@@ -8,8 +8,8 @@ class PDInterface:
     def __init__(self, code1, code2):
         self.u = itkdb.core.User(accessCode1=code1, accessCode2=code2)
         self.pd_client = itkdb.Client(user=self.u)
-        #with open("{}/itkpd-interface/config/stage_test.json".format(VIEWER_DIR)) as f:
-        #    self.stage_test_map = json.load(f)
+        with open("{}/itkpd-interface/config/stage_test.json".format(VIEWER_DIR)) as f:
+            self.stage_test_map = json.load(f)
 
     def getCompFromLocalDB(self, sn):
         query = {"serialNumber": sn,"proDB": True}
@@ -19,7 +19,13 @@ class PDInterface:
         m_doc = self.getCompFromLocalDB(msn)
         cprs = localdb.childParentRelation.find({"parent":str(m_doc["_id"])})
         chip_ids = [ chip["child"] for chip in cprs ]
-        return [localdb.component.find_one({"_id":ObjectId(chip_id)}) for chip_id in chip_ids]
+        docs = []
+        for chip_id in chip_ids:
+            doc = localdb.component.find_one({"_id":ObjectId(chip_id), "componentType":"front-end_chip"})
+            if doc != None:
+                logger.info( '{}'.format( doc ) )
+                docs.append( doc )
+        return docs
 
     def getQmsFromLocalDB(self, oid):
         query = {"component": oid}
diff --git a/viewer/itkpd-interface/lib/download_QC_info.py b/viewer/itkpd-interface/lib/download_QC_info.py
index 02a2ca1f..52f4b087 100755
--- a/viewer/itkpd-interface/lib/download_QC_info.py
+++ b/viewer/itkpd-interface/lib/download_QC_info.py
@@ -82,8 +82,22 @@ class ModuleDownloader(PDInterface.PDInterface):
                     continue
                 
                 for testType in stage["testTypes"]:
-                    test_item_map[testType["testType"]["code"]] = testType["testType"]["name"]
-                    test_items.append(testType["testType"]["code"])
+                    code = testType["testType"]["code"]
+                    name = testType["testType"]["name"]
+                    
+                    temperatures = [30, 20, -15]
+                    excepCodes = [ "READOUT_IN_BASIC_ELECTRICAL_TEST", "TUNING", "BUMP_BOND_QUALITY", "SENSOR_IV" ]
+                    
+                    if code in excepCodes:
+                        for T in temperatures:
+                            code_var = code + "_{}{}DEG".format( "MINUS" if T < 0 else "", abs(T) )
+                            name_var = name + " ({} degC)".format( T )
+                            test_item_map[code_var] = name_var
+                            test_items.append( code_var )
+                    else:
+                        test_item_map[code] = name
+                        test_items.append( code )
+            
             stage_flow.append(stage["code"])
             stage_vs_test[stage["code"]] = test_items
 
@@ -112,7 +126,8 @@ class ModuleDownloader(PDInterface.PDInterface):
             "latestSyncedStage"  : cpt_doc["currentStage"]["code"],
             "status"             : "created",
             "rework_stage"       : [],
-            "QC_results"         : {}
+            "QC_results"         : {},
+            "QC_results_pdb"     : {}
         }
 
         chipType = ""
@@ -129,8 +144,10 @@ class ModuleDownloader(PDInterface.PDInterface):
         for stage in qcStatus["stage_flow"]:
             tests = qcStatus["stage_test"][stage]
             doc["QC_results"][stage] = {}
+            doc["QC_results_pdb"][stage] = {}
             for test in tests:
                 doc["QC_results"][stage][test] = "-1"
+                doc["QC_results_pdb"][stage][test] = "-1"
         
         return doc
 
@@ -141,6 +158,9 @@ class ModuleDownloader(PDInterface.PDInterface):
         logger.info("Start downloading info of stages and QC tests")
         if userdb.QC.status.find_one( {"proddbVersion":proddbv, "code":module_cpt_doc["code"] }) == None:
             userdb.QC.status.insert_one( self.__create_QC_status_doc(module_cpt_doc) )
+        else:
+            userdb.QC.status.remove( {"proddbVersion":proddbv, "code":module_cpt_doc["code"] })
+            userdb.QC.status.insert_one( self.__create_QC_status_doc(module_cpt_doc) )
         logger.info("Finished!!\n")
 
         return 0
@@ -201,10 +221,11 @@ class ModuleDownloader(PDInterface.PDInterface):
         # If the QC record is blank, insert one
         if cpt_qc_localdb_record == None:
             localdb.QC.module.status.insert_one( cpt_qc_doc )
-            logger.info( "Created QC status doc for {} {}.".format( cpt_type, cpt_sn ) )
         else:
-            logger.info( "QC status doc for {} {} is already present.".format( cpt_type, cpt_sn ) )
+            localdb.QC.module.status.remove(  {"component": cpt_doc["id"], "proddbVersion":proddbv}  )
+            localdb.QC.module.status.insert_one( cpt_qc_doc )
             
+        logger.info( "Created QC status doc for {} {}.".format( cpt_type, cpt_sn ) )
         return cpt_localdb_doc
         
         
diff --git a/viewer/itkpd-interface/lib/upload_results.py b/viewer/itkpd-interface/lib/upload_results.py
index 98de8d21..4f1507e4 100755
--- a/viewer/itkpd-interface/lib/upload_results.py
+++ b/viewer/itkpd-interface/lib/upload_results.py
@@ -6,46 +6,155 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../
 from functions.imports import *
 
 class QCResultUploader(PDInterface.PDInterface):
+    
+    def __upload( self, testSpecificCallback ):
+        
+        # self.ldb_component             = super().getCompFromLocalDB(componentSerialNumber)
+        # self.ldb_componentId           = str( self.ldb_component["_id"] )
+        # self.ldb_componentType         = self.ldb_component["componentType"]
+        # self.ldb_component_QC_info     = super().getQmsFromLocalDB(self.ldb_componentId)
+        # self.ldb_component_prop_info   = super().getPmsFromLocalDB(self.ldb_componentId)
+        # self.ldb_test_doc              = super().getQrFromLocalDB(result_id)
+        # self.pdb_component_doc         = super().getCompFromProdDB(componentSerialNumber)
+        # self.pdb_prev_testRuns         = [test for test in self.pd_client.get("listTestRunsByComponent", json={"component": self.pdb_component_doc["code"] }) ]
+        
+        isUploaded = False
+        
+        logger.info( '__upload(): processing stage {} / test type {}'.format( self.ldb_test_doc['currentStage'], self.testType ) )
+
+        timestampAsString = self.__getQCStrTime( self.ldb_test_doc["sys"]["cts"] )
+        
+        isFreshResult = True
+        
+        goodTestRunIDs = []
+        sameEnvGoodTestRunIDs = []
+        
+        # loop over ProdDB tests
+        for prevTest in self.pdb_component_doc['tests']:
+            if prevTest['code'] != self.testType:
+                continue
+            
+            testRuns = prevTest['testRuns']
+            
+            for testRun in testRuns:
+                if testRun['state'] != 'ready':
+                    continue
+                    
+                goodTestRunIDs.append( testRun['id'] )
+                
+                try:
+                    env_temp = testRun['properties']["ENVIRONMENT_TEMPERATURE"]
+                    if int( env_temp ) == int( self.testSetTemp ):
+                        sameEnvGoodTestRunIDs.append( testRun['id'] )
+                except:
+                    pass
+                
+                if testRun['runNumber'] == str( self.ldb_test_doc["_id"] ):
+                    isFreshResult = False
+                    self.pdb_testRunId = testRun['id']
+                    
+        logger.info( '__upload(): good testRun ids: {}'.format( goodTestRunIDs ) )
+        
+        
+        if isFreshResult:
+            
+            logger.info( 'This is a fresh test run, uploading' )
+            pprint.pprint( testSpecificCallback )
+            
+            # Force set the component stage on ProdDB to this stage
+            try:
+                self.pd_client.post( 'setComponentStage', json = { 'component':self.componentSerialNumber, 'stage':self.stage } )
+                
+            except Exception as e:
+                logger.error( '{}'.format(e) )
+                
+            logger.info( 'Changed the ProdDB {} stage to {}'.format( self.componentSerialNumber, self.stage ) )
+            
+            if self.ldb_componentType == "module":
+                
+                if self.testType == "READOUT_IN_BASIC_ELECTRICAL_TEST":
+                    test_result = testSpecificCallback()
+                    self.__createRawResultAttachment( test_result )
+                    
+                else:
+                    json = testSpecificCallback( self.__createTestTemplate(timestampAsString), timestampAsString )
+                    test_result = self.pd_client.post( "uploadTestRunResults", json=json )
+                    
+                    #pprint.pprint( test_result )
+            
+                self.pdb_testRunId = test_result['testRun']['id']
+            
+                    
+                if self.testType == "OPTICAL":
+                    pic_name = self.ldb_test_doc["currentStage"] + "_optical_img" + ".png"
+                    inspect_pic = self.ldb_test_doc["results"]["img_entire"]["target"]
+                    data = fs.get(ObjectId(str(inspect_pic))).read()
+                    with open(pic_name, 'wb') as f:
+                        f.write(data)
+                        f = open(pic_name, "rb")
+                        os.remove(pic_name)
+                        self.pd_client.post("createBinaryTestRunParameter", data=dict(testRun=test_result["testRun"]["id"], parameter="FULL_IMAGE"), files=dict(data=f) )
+                        f.close()
+                    
+                    self.__AttachGoldens()
+            
+            # if the test is exclusive, delete all the rest
+            # otherwise, delete only testRuns with the same temperature
+            if self.isExclusiveTest:
+                logger.info( 'This is an exclusive test, delete previous TestRun records...' )
+                for tr_id in goodTestRunIDs:
+                    self.pd_client.post("deleteTestRun", json = { "testRun": tr_id } )
+                    logger.info( 'deleted testRun {}'.format( tr_id ) )
+            else:
+                for tr_id in sameEnvGoodTestRunIDs:
+                    self.pd_client.post("deleteTestRun", json = { "testRun": tr_id } )
+                    logger.info( 'deleted testRun {}'.format( tr_id ) )
+            
+            isUploaded = True
+        else:
+            logger.info( 'The test run is already recorded on ProdDB and is a ready state, skipping' )
+        
 
-    def __upload_functions(self, module_doc, result_doc, test_item, QC_info):
-
-        if len(result_doc) == 1:
+        logger.info("Finished!!\n")
+        #time.sleep(1)
+    
+        return isUploaded
+        
+        
+    '''
+    def __upload_functions(self, test_item, QC_info):
+        
+
+        if len(self.ldb_test_doc) == 1:
             logger.info("This result format is not proper.")
             return
 
-        stageVersion = self.stage_test_map["stage_flows"][QC_info.get("stageVersion", "RD53A")]
-        for test in stageVersion[result_doc["currentStage"]]:
-            #if test["ldb_testType"] == "METROLOGY":
-            #    if "PI" in module_doc["serialNumber"] and not "M1" in module_doc["serialNumber"] and not "RA" in module_doc["serialNumber"]:
-            #        result_doc["testType"] = "METROLOGY_TRIPLET"
-            #    else:
-            #        result_doc["testType"] = "METROLOGY_QUAD"
-            if test["ldb_testType"] == result_doc["testType"]:
-                result_doc["testType"] = test["pdb_testType"]
-                break
-
         functions = {
-            "OPTICAL"                         :  self.__upload_VI,
-            "PIXEL_FAILURE_TEST"              :  self.__upload_electrical,
-            "READOUT_IN_BASIC_ELECTRICAL"     :  self.__upload_electrical,
-            "METROLOGY"                       :  self.__upload_metrology,
-            "METROLOGY_QUAD"                  :  self.__upload_metrologyquad,
-            "METROLOGY_TRIPLET"               :  self.__upload_metrologytriplet,
-            "BACKSIDE_COPLANARITY"            :  self.__upload_coplanarity,
-            "SENSOR_IV"                       :  self.__upload_SensorIV,
-            "SLDO_VI"                         :  self.__upload_SLDOVI,
-            "MASS"                            :  self.__upload_mass,
-            "GLUE_MODULE_FLEX_ATTACH"         :  self.__upload_glueInformation,
-            "WIREBONDING"                     :  self.__upload_wirebonding,
-            "WIREBOND"                        :  self.__upload_wirebond,
-            "PARYLENE"                        :  self.__upload_parylene,
-            "THERMALCYCLE"                    :  self.__upload_thermal,
-            "ADC_CALIBRATION"                 :  self.__upload_adccalibration,
-            "TUNING"                          :  self.__upload_tuning
+            "OPTICAL"                                :  self.__upload_VI,
+            "READOUT_IN_BASIC_ELECTRICAL_TEST"       :  self.__upload_electrical,
+            "METROLOGY"                              :  self.__upload_metrology,
+            "QUAD_METROLOGY"                         :  self.__upload_metrologyquad,
+            "TRIPLET_METROLOGY"                      :  self.__upload_metrologytriplet,
+            "FLATNESS"                               :  self.__upload_coplanarity,
+            "SENSOR_IV"                              :  self.__upload_SensorIV,
+            "SLDO_VI"                                :  self.__upload_SLDOVI,
+            "MASS"                                   :  self.__upload_mass,
+            "GLUE_MODULE_FLEX_ATTACH"                :  self.__upload_glueInformation,
+            "WIREBONDING"                            :  self.__upload_wirebonding,
+            "WIREBOND"                               :  self.__upload_wirebond,
+            "PARYLENE"                               :  self.__upload_parylene,
+            "THERMALCYCLE"                           :  self.__upload_thermal,
+            "ADC_CALIBRATION"                        :  self.__upload_adccalibration,
+            "TUNING"                                 :  self.__upload_tuning
             #"WP_ENVELOPE"                     :  self.__upload_wpenvelope
         }
-
-        if result_doc != {} and result_doc["testType"] in functions: functions[result_doc["testType"]](module_doc, result_doc, test_item)
+        
+        ti = test_item.replace("_30DEG", "").replace("_20DEG", "").replace("_MINUS15DEG", "")
+        
+        self.ldb_test_doc['testType'] = ti
+        
+        if self.ldb_test_doc != {} and ti in functions:
+            functions[ti](self.pdb_component_doc, self.ldb_test_doc, ti )
         else: logger.info("There is no uploading function.")
         return
 
@@ -60,348 +169,349 @@ class QCResultUploader(PDInterface.PDInterface):
             "ORIENTATION"               : self.__upload_orientation
         }
 
-        if prop_doc != {} and prop_doc["testType"] in prop_functions: prop_functions[prop_doc["testType"]](module_doc, prop_doc)
+        if prop_doc != {} and prop_doc["testType"] in prop_functions: prop_functions[prop_doc["testType"]](self.pdb_component_doc, prop_doc)
         else: logger.info("There is no uploading function.")
         return
 
 
 ########################
 ## for non-electrical ##
-    def __upload_VI(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_VI(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createOpticalTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-            attach_golden_imgs = self.__AttachGoldens(result_doc, new_test_result, test_item)
+            new_test_result = self.__createOpticalTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
+            attach_golden_imgs = self.__AttachGoldens(new_test_result)
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createOpticalTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                attach_golden_imgs = self.__AttachGoldens(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createOpticalTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                attach_golden_imgs = self.__AttachGoldens(new_test_result)
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_metrology(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_metrology(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createMetrologyTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createMetrologyTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createMetrologyTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createMetrologyTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_metrologyquad(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_metrologyquad(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createMetrologyQuadTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createMetrologyQuadTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createMetrologyQuadTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createMetrologyQuadTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_metrologytriplet(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_metrologytriplet(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createMetrologyTripletTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createMetrologyTripletTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createMetrologyTripletTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createMetrologyTripletTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_coplanarity(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_coplanarity(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createCoplanarityTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createCoplanarityTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createCoplanarityTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createCoplanarityTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_SensorIV(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_SensorIV(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
-                tr_doc["testType"]["code"] = test_item
+                tr_doc["testType"]["code"] = self.testType
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    if old_result_doc["0"]["testType"] == test_item:
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    if previous_ldb_test_doc["0"]["testType"] == self.testType:
                         result_counter = result_counter + 1
-                        old_result_docs.append(old_result_doc["0"]["_id"])
+                        previous_ldb_test_docs.append(previous_ldb_test_doc["0"]["_id"])
                 except:
                     logger.warning("this is not localdb results")
 
         if result_counter == 0:
-            new_test_result = self.__createSensorIVTestRun(result_doc, module_doc, str_date, test_item)
-            result_doc.pop("old_tests")
-            self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createSensorIVTestRun(timestampAsString, self.testType)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 try:
                     shutil.rmtree(cache_dir)
                 except:
                     pass
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createSensorIVTestRun(result_doc, module_doc, str_date, test_item)
-                result_doc.pop("old_tests")
-                self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_docs[i], new_test_result["testRun"]["id"], old_result_docs[i])
+                new_test_result = self.__createSensorIVTestRun(timestampAsString, self.testType)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                self.__createRawResultAttachment()
+                #self.__deleteResult(tr_docs[i], new_test_result["testRun"]["id"], previous_ldb_test_docs[i])
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_SLDOVI(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_SLDOVI(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createSLDOVITestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createSLDOVITestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createSLDOVITestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createSLDOVITestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_mass(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_mass(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createMassTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createMassTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createMassTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createMassTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_glueInformation(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_glueInformation(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createGlueTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createGlueTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createGlueTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createGlueTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_wirebonding(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_wirebonding(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createWirebondingTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            attach_bonding_program = self.__attachBondingProgram(result_doc, new_test_result)
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createWirebondingTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            attach_bonding_program = self.__attachBondingProgram(self.ldb_test_doc, new_test_result)
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createWirebondingTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                attach_bonding_program = self.__attachBondingProgram(result_doc, new_test_result)
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createWirebondingTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                attach_bonding_program = self.__attachBondingProgram(self.ldb_test_doc, new_test_result)
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
+    '''
 
-    def __attachBondingProgram(self, result_doc, new_test_result):
+    def __attachBondingProgram(self, localdb_test_doc, new_test_result):
         try:
             fsb = gridfs.GridFSBucket(localdb)
             bond_file = open('static/Bonding_Program.dat','wb+')
-            fsb.download_to_stream(ObjectId(result_doc["results"]["property"]["Bond_program"]), bond_file)
+            fsb.download_to_stream(ObjectId(self.ldb_test_doc["results"]["property"]["Bond_program"]), bond_file)
             bond_file.seek(0)
             contents = bond_file.read()
         except:
@@ -413,109 +523,111 @@ class QCResultUploader(PDInterface.PDInterface):
         self.pd_client.post( "createTestRunAttachment", data=dict( testRun=new_test_result["testRun"]["id"], type="file" ), files=page_attachment )
         return  os.remove('static/Bonding_Program.dat')
 
-    def __upload_wirebond(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    '''
+    def __upload_wirebond(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createWirebondTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createWirebondTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createWirebondTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createWirebondTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_parylene(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_parylene(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"] == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"] == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun": tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createParyleneTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createParyleneTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createParyleneTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createParyleneTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_thermal(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_thermal(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createThermalTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            attach_bonding_program = self.__attachThermalProgram(result_doc, new_test_result)
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createThermalTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            attach_bonding_program = self.__attachThermalProgram(self.ldb_test_doc, new_test_result)
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createThermalTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                attach_bonding_program = self.__attachThermalProgram(result_doc, new_test_result)
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createThermalTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                attach_bonding_program = self.__attachThermalProgram(self.ldb_test_doc, new_test_result)
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
+    '''
 
-    def __attachThermalProgram(self, result_doc, new_test_result):
+    def __attachThermalProgram(self, localdb_test_doc, new_test_result):
         try:
             fsb = gridfs.GridFSBucket(localdb)
             temp_file = open('static/Thermal_temp.json', 'wb+')
-            fsb.download_to_stream(ObjectId(result_doc["results"]["Temperature_log"]), temp_file)
+            fsb.download_to_stream(ObjectId(self.ldb_test_doc["results"]["Temperature_log"]), temp_file)
             temp_file.seek(0)
             contents = temp_file.read()
         except:
@@ -531,7 +643,7 @@ class QCResultUploader(PDInterface.PDInterface):
             fsb = gridfs.GridFSBucket(localdb)
             humid_file = open('static/Thermal_humid.json', 'wb+')
             fsb.download_to_stream(
-                ObjectId(result_doc["results"]["Humidity_log"]), humid_file)
+                ObjectId(self.ldb_test_doc["results"]["Humidity_log"]), humid_file)
             humid_file.seek(0)
             contents = humid_file.read()
         except:
@@ -550,129 +662,132 @@ class QCResultUploader(PDInterface.PDInterface):
 
         return
 
-    def __upload_adccalibration(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    '''
+    def __upload_adccalibration(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"] == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"] == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun": tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createADCcalibrationTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createADCcalibrationTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createADCcalibrationTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createADCcalibrationTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_tuning(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_tuning(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"] == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"] == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun": tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createTuningTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createTuningTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createTuningTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createTuningTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
 
-    def __upload_wpenvelope(self, module_doc, result_doc, test_item):
-        qr_oid = result_doc["_id"]
+    def __upload_wpenvelope(self):
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"] == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        previous_ldb_test_docs = []
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"] == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 result_counter = result_counter + 1
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun": tr["id"]})
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    old_result_docs.append(old_result_doc['0']['_id'])
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                 except:
                     logger.warning("This is not LocalDB result")
         if result_counter == 0:
-            new_test_result = self.__createWPenvelopeTestRun(result_doc, module_doc, str_date)
-            result_doc.pop("old_tests")
-            new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
+            new_test_result = self.__createWPenvelopeTestRun(timestampAsString)
+            self.ldb_test_doc.pop("pdb_prev_testRuns")
+            new_test_attachment = self.__createRawResultAttachment()
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 #                shutil.rmtree("{}/attachments".format("."))
                 logger.info("This result is already uploaded.")
             else:
-                new_test_result = self.__createWPenvelopeTestRun(result_doc, module_doc, str_date)
-                result_doc.pop("old_tests")
-                new_test_attachment = self.__createRawResultAttachment(result_doc, new_test_result, test_item)
-                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], old_result_doc)
+                new_test_result = self.__createWPenvelopeTestRun(timestampAsString)
+                self.ldb_test_doc.pop("pdb_prev_testRuns")
+                new_test_attachment = self.__createRawResultAttachment()
+                #self.__deleteResult(tr_doc, new_test_result["testRun"]["id"], previous_ldb_test_doc)
 
         logger.info("Finished!!\n")
         #time.sleep(1)
+    '''
 
-####################
-## for electrical ##
-## main function
-    def __upload_electrical(self, module_doc, result_doc, test_item):
+    ####################
+    ## for electrical ##
+    ## main function
+    '''
+    def __upload_electrical(self):
         #check if a result is already uploaded or not
-        qr_oid = result_doc["_id"]
+        qr_oid = self.ldb_test_doc["_id"]
         qr_doc = super().getQrFromLocalDB(qr_oid)
-        str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
+        timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
         result_counter = 0
-        old_result_docs = []
+        previous_ldb_test_docs = []
         tr_docs = []
-        for tr in result_doc["old_tests"]:
-            if tr["state"]  == "ready" and tr["testType"]["code"] == result_doc["testType"] and tr["stage"]["code"] == result_doc["currentStage"]:
+        for tr in self.ldb_test_doc["pdb_prev_testRuns"]:
+            if tr["state"]  == "ready" and tr["testType"]["code"] == self.testType and tr["stage"]["code"] == self.ldb_test_doc["currentStage"]:
                 tr_doc = self.pd_client.get("getTestRun", json={"testRun":tr["id"]})
-                tr_doc["testType"]["code"] = test_item
+                tr_doc["testType"]["code"] = self.testType
                 try:
-                    old_result_doc = self.__getOldResult(tr_doc)
-                    if old_result_doc["0"]["testType"] == test_item:
+                    previous_ldb_test_doc = self.__getOldResult(tr_doc)
+                    if previous_ldb_test_doc["0"]["testType"] == self.testType:
                         result_counter = result_counter + 1
-                        old_result_docs.append(old_result_doc['0']['_id'])
+                        previous_ldb_test_docs.append(previous_ldb_test_doc['0']['_id'])
                         tr_docs.append(tr_doc)
                 except:
                     logger.warning("Results not uploaded from LocalDB exist")
         if result_counter == 0:
-            self.__create_electrial_pdb(module_doc, result_doc, test_item)
+            self.__create_electrial_pdb(self.pdb_component_doc, self.ldb_test_doc, self.testType)
         else:
-            if str(result_doc["_id"]) in old_result_docs:
+            if str(self.ldb_test_doc["_id"]) in previous_ldb_test_docs:
                 try:
                     shutil.rmtree(cache_dir)
                 except:
@@ -680,25 +795,26 @@ class QCResultUploader(PDInterface.PDInterface):
                 logger.info("This result is already uploaded.")
                 return
             else:
-                self.__create_electrial_pdb(module_doc, result_doc, test_item)
+                self.__create_electrial_pdb(self.pdb_component_doc, self.ldb_test_doc, self.testType)
                 #for result in tr_docs[i]['results']:
                 #    if result['code'] == "RESULT_IDS":
                 #        for scan_id in result['value']:
                 #            self.pd_client.post("deleteTestRun", json={"testRun": scan_id})
-                #self.__deleteResult(tr_docs[i], new_test_result["testRun"]["id"], old_result_docs[i])
+                #self.__deleteResult(tr_docs[i], new_test_result["testRun"]["id"], previous_ldb_test_docs[i])
 
         logger.info("Finished!!\n")
         return
         #time.sleep(1)
+    '''
 
 
-    def __create_electrial_pdb(self, module_doc, result_doc, test_item):
+    def __create_electrial_pdb(self):
         cp_test_map = {}
-        str_date = None
+        timestampAsString = None
         scans = []
 
         #create cache files
-        for i, d_ in enumerate(result_doc["results"]["scans"]):
+        for i, d_ in enumerate(self.ldb_test_doc["results"]["scans"]):
             scanType, tr_oid = d_["name"], d_["runId"]
             scans.append(d_["name"])
             path = "{}/{}".format(IF_DIR,d_["name"])
@@ -706,54 +822,55 @@ class QCResultUploader(PDInterface.PDInterface):
             command = ["{}/itkpd-interface/localdb-interface/bin/localdbtool-retrieve".format(VIEWER_DIR), "pull", "--test", d_["runId"], "--directory", path]
             subprocess.call(command)
             if i == 0:
-                qr_doc = super().getQrFromLocalDB(result_doc["_id"])
-                str_date = self.__getQCStrTime(qr_doc["sys"]["cts"])
-#                tr_doc = super().getTrFromLocalDB(tr_oid)
-#                str_date = self.__getStrTime(tr_doc["timestamp"])
-
-# fix scan result's files if component name is changed
+                qr_doc = super().getQrFromLocalDB(self.ldb_test_doc["_id"])
+                timestampAsString = self.__getQCStrTime(qr_doc["sys"]["cts"])
+                #                tr_doc = super().getTrFromLocalDB(tr_oid)
+                #                timestampAsString = self.__getStrTime(tr_doc["timestamp"])
+                
+            # fix scan result's files if component name is changed
             scan_files = os.listdir(path)
 
             # create relationship between past & new components
-            old_chips = []
+            previous_chips = []
             new_chips = []
-            old_module_name = ""
+            previous_module_name = ""
             new_module_name = ""
             compTestRun = localdb.componentTestRun.find({"testRun" : d_["runId"]})
             for item in compTestRun:
                 if "scanSN" in item:
                     if item["chip"] == "module":
-                        old_module_name = item["scanSN"]
+                        previous_module_name = item["scanSN"]
                         new_module_name = item["name"]
                     else:
-                        old_chips.append(item["scanSN"])
+                        previous_chips.append(item["scanSN"])
                         new_chips.append(item["name"])
 
-            if old_module_name:
+            if previous_module_name:
                 # fix contents of scan files
                 for file in scan_files:
                     f1 = open(path + "/" + file, 'r', encoding='utf-8').read()
                     f2 = open(path + "/" + file, 'w', encoding='utf-8')
-                    for i in range(len(old_chips)):
-                        f1 = f1.replace(old_chips[i], new_chips[i])
+                    for i in range(len(previous_chips)):
+                        f1 = f1.replace(previous_chips[i], new_chips[i])
                     if file == "connectivity.json" or file == "scanLog.json":
-                        f1 = f1.replace(old_module_name, new_module_name)
+                        f1 = f1.replace(previous_module_name, new_module_name)
                         f1 = f1.replace(path + "//", "/")
                     f2.write(f1)
 
                 # fix file name
                 for file in scan_files:
-                    for i in range(len(old_chips)):
-                        if old_chips[i] in file:
-                            new_file = file.replace(old_chips[i], new_chips[i])
+                    for i in range(len(previous_chips)):
+                        if previous_chips[i] in file:
+                            new_file = file.replace(previous_chips[i], new_chips[i])
                             os.rename(path + "/" + file, path + "/" + new_file)
 
         #for FE chips
-        fe_docs = super().getFEchipsDocs(module_doc["serialNumber"])
+        fe_docs = super().getFEchipsDocs(self.pdb_component_doc["serialNumber"])
         for fe_doc in fe_docs:
-            new_test_result = self.__createElecTestRunForFEChip(result_doc, fe_doc["serialNumber"], str_date)
+            new_test_result = self.__createElecTestRunForFEChip(fe_doc["serialNumber"], timestampAsString)
             cp_test_map[fe_doc["serialNumber"]] = new_test_result["testRun"]["id"]
             for scan in scans:
+                logger.info('{}'.format( scan ) )
                 zip_name = "{}_{}".format(fe_doc["serialNumber"],scan)
                 zip_path = "{0}/{1}.zip".format(IF_DIR, zip_name)
                 if os.path.exists(zip_path): os.remove(zip_path)
@@ -766,11 +883,13 @@ class QCResultUploader(PDInterface.PDInterface):
                 self.__attachFileToTestRun(zip_path, scan + ".zip", cp_test_map[fe_doc["serialNumber"]])
 
         #for module
-        new_module_result = self.__createElecTestRunForModule(result_doc, module_doc, str_date, cp_test_map, test_item)
-        result_doc.pop("old_tests")
-        new_test_attachment = self.__createRawResultAttachment(result_doc, new_module_result, test_item)
+        new_module_result = self.__createElecTestRunForModule(timestampAsString, cp_test_map, self.testType)
+        logger.info('here')
+        new_test_attachment = self.__createRawResultAttachment( new_module_result )
+        logger.info('here')
         for i, scan in enumerate(scans):
-            zip_name = "{}_{}".format(module_doc["serialNumber"],scan)
+            logger.info('here2 {}'.format( scan ) )
+            zip_name = "{}_{}".format(self.pdb_component_doc["serialNumber"],scan)
             zip_path = "{0}/{1}.zip".format(IF_DIR, zip_name)
             if os.path.exists(zip_path): os.remove(zip_path)
             zip_file = zipfile.ZipFile(zip_path, "a", zipfile.ZIP_DEFLATED)
@@ -779,7 +898,7 @@ class QCResultUploader(PDInterface.PDInterface):
                 filename = filepath.split("/")[-1]
                 if i == 0 and (filename.split(".")[0] in [ "dbCfg", "userCfg", "siteCfg" ]): self.__attachFileToTestRun(filepath, filename, new_module_result["testRun"]["id"])
                 if filename.split(".")[0] in [ scan, "scanLog"]:
-                    if filename.split(".")[0] == "scanLog": self.__modifyScanLog(filepath, result_doc["currentStage"])
+                    if filename.split(".")[0] == "scanLog": self.__modifyScanLog(filepath, self.ldb_test_doc["currentStage"])
                     zip_file.write(filepath, filename)
 
             zip_file.close()
@@ -787,8 +906,9 @@ class QCResultUploader(PDInterface.PDInterface):
 
         # attach the best configs to the module's top page.
         for scan in scans:
+            logger.info('here3 {}'.format( scan ) )
             if scan == "std_thresholdscan":
-                zip_name = "{}_{}_degree_{}".format("BestCfg",str(self.__getElecTestSettingTemp(result_doc, test_item)).replace("-","minus"), result_doc["currentStage"])
+                zip_name = "{}_{}_degree_{}".format("BestCfg",str(self.testSetTemp).replace("-","minus"), self.ldb_test_doc["currentStage"])
                 zip_path = "{0}/{1}.zip".format(IF_DIR, zip_name)
                 if os.path.exists(zip_path): os.remove(zip_path)
                 zip_file = zipfile.ZipFile(zip_path, "a", zipfile.ZIP_DEFLATED)
@@ -796,7 +916,7 @@ class QCResultUploader(PDInterface.PDInterface):
                     filepath = "{}/{}/{}".format(IF_DIR,scan,fe_doc["serialNumber"] + ".json.after")
                     if os.path.exists(filepath): zip_file.write(filepath, filepath.split("/")[-1])
                 zip_file.close()
-                self.__attachFileToComp(zip_path, zip_name + ".zip", module_doc)
+                self.__attachFileToComp(zip_path, zip_name + ".zip", self.pdb_component_doc)
 
         return new_module_result
 
@@ -808,24 +928,24 @@ class QCResultUploader(PDInterface.PDInterface):
     def __upload_pullupregistor(self, module_doc, prop_doc):
         pr_oid = prop_doc["_id"]
         pr_doc = super().getQrFromLocalDB(pr_oid)
-        new_prop_result = self.__createPullupTestRun(prop_doc, module_doc)
-        new_prop_attachment = self.__createPropertyAttachment(prop_doc, module_doc)
+        new_prop_result = self.__createPullupTestRun(prop_doc, self.pdb_component_doc)
+        new_prop_attachment = self.__createPropertyAttachment(prop_doc, self.pdb_component_doc)
 
         logger.info("Finished!!\n")
 
     def __upload_ireftrim(self, module_doc, prop_doc):
         pr_oid = prop_doc["_id"]
         pr_doc = super().getQrFromLocalDB(pr_oid)
-        new_prop_result = self.__createIreftrimTestRun(prop_doc, module_doc)
-        new_prop_attachment = self.__createPropertyAttachment(prop_doc, module_doc)
+        new_prop_result = self.__createIreftrimTestRun(prop_doc, self.pdb_component_doc)
+        new_prop_attachment = self.__createPropertyAttachment(prop_doc, self.pdb_component_doc)
 
         logger.info("Finished!!\n")
 
     def __upload_orientation(self, module_doc, prop_doc):
         pr_oid = prop_doc["_id"]
         pr_doc = super().getQrFromLocalDB(pr_oid)
-        new_prop_result = self.__createOrientationTestRun(prop_doc, module_doc)
-        new_prop_attachment = self.__createPropertyAttachment(prop_doc, module_doc)
+        new_prop_result = self.__createOrientationTestRun(prop_doc, self.pdb_component_doc)
+        new_prop_attachment = self.__createPropertyAttachment(prop_doc, self.pdb_component_doc)
 
         logger.info("Finished!!\n")
 
@@ -845,81 +965,81 @@ class QCResultUploader(PDInterface.PDInterface):
 
         return  this_time
 
-    def __createTestTemplate(self, doc, testType, str_date):
-        project = {"project": doc["project"]["code"]}
-        componentType = {"componentType": doc["componentType"]["code"]}
-        pd_testType = {"code": testType}
+    def __createTestTemplate(self, timestampAsString):
+        
+        project = {"project": self.pdb_component_doc["project"]["code"]}
+        componentType = {"componentType": self.pdb_component_doc["componentType"]["code"]}
+        pd_testType = {"code": self.testType}
 
         test_template = self.pd_client.get("generateTestTypeDtoSample", json={**project, **componentType, **pd_testType})
+        
         json_template = {
             **test_template,
-            "component": doc["serialNumber"],
-            "institution": doc["currentLocation"]["code"],
-            "date": str_date
+            "component": self.pdb_component_doc["serialNumber"],
+            "institution": self.pdb_component_doc["currentLocation"]["code"],
+            "date": timestampAsString,
+            "runNumber": str( self.ldb_test_doc["_id"] )
         }
 
         return json_template
 
-    def __createRawResultAttachment(self, result_doc, new_test_result, test_item):
-        attachment_doc = result_doc
+    def __createRawResultAttachment(self, test_result ):
+        attachment_doc = self.ldb_test_doc
         attachment_doc["_id"] = str(attachment_doc["_id"])
-        pdb_testType = result_doc["testType"]
-        attachment_doc["sys"]["cts"] = result_doc["sys"]["cts"].isoformat()
-        attachment_doc["sys"]["mts"] = result_doc["sys"]["mts"].isoformat()
-        if "PIXEL_FAILURE_TEST" in result_doc["testType"]:
+        pdb_testType = self.testType
+        
+        pprint.pprint( self.ldb_test_doc )
+        
+        try:
+            attachment_doc["sys"]["cts"] = self.ldb_test_doc["sys"]["cts"].isoformat()
+            attachment_doc["sys"]["mts"] = self.ldb_test_doc["sys"]["mts"].isoformat()
+            attachment_doc["startTime"] = self.ldb_test_doc["startTime"].isoformat()
+        except:
             try:
-                attachment_doc["startTime"] = result_doc["startTime"].isoformat()
+                attachment_doc["sys"]["cts"] = self.ldb_test_doc["sys"]["cts"]
+                attachment_doc["sys"]["mts"] = self.ldb_test_doc["sys"]["mts"]
+                attachment_doc["startTime"] = self.ldb_test_doc["startTime"]
             except:
                 pass
-        f = open(result_doc["testType"] + '_results.json', 'w')
-        attachment_doc["testType"] = str(test_item)
+        
+        f = open(self.testType + '_results.json', 'w')
+        attachment_doc["testType"] = str(self.testType)
+        #logger.info( 'attachment_doc = {}'.format( attachment_doc ) )
         json.dump(attachment_doc, f, indent=4)
         f.close()
 
         attachment_file = open(pdb_testType + '_results.json', 'rb')
         page_attachment = {"data": (pdb_testType + '_results.json', attachment_file, "json")}
 
-        self.pd_client.post( "createTestRunAttachment", data=dict( testRun=new_test_result["testRun"]["id"], type="file" ), files=page_attachment )
+        self.pd_client.post( "createTestRunAttachment", data=dict( testRun = test_result["testRun"]["id"], type="file" ), files=page_attachment )
         return  os.remove(pdb_testType + '_results.json')
 
 
     #######################
     ## for Optical Inspection
-    def __createOpticalTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
+    def __createOpticalTestRun(self, json, timestampAsString):
         json["results"]["FULL_IMAGE"] = ""
-        new_test_result = self.pd_client.post("uploadTestRunResults",json=json)
-
-        pic_name = result_doc["currentStage"] + "_optical_img" + ".png"
-        inspect_pic = result_doc["results"]["img_entire"]["target"]
-        data = fs.get(ObjectId(str(inspect_pic))).read()
-        with open(pic_name, 'wb') as f:
-            f.write(data)
-        f = open(pic_name, "rb")
-        os.remove(pic_name)
-        self.pd_client.post("createBinaryTestRunParameter", data=dict(testRun=new_test_result["testRun"]["id"], parameter="FULL_IMAGE"), files=dict(data=f) )
-        f.close()
 
-        return new_test_result
+        return json
 
-    def __AttachGoldens(self, result_doc, new_test_result, test_item):
-        target_name = str(result_doc["results"]["img_entire"]["target"]) + ".png"
-        target_pic = result_doc["results"]["img_entire"]["target"]
+    def __AttachGoldens(self, new_test_result):
+        target_name = str(self.ldb_test_doc["results"]["img_entire"]["target"]) + ".png"
+        target_pic = self.ldb_test_doc["results"]["img_entire"]["target"]
         data_target = fs.get(ObjectId(str(target_pic))).read()
         with open(target_name, 'wb') as f:
             f.write(data_target)
 
-        golden_name = str(result_doc["results"]["img_entire"]["reference"]) + ".png"
-        golden_pic = result_doc["results"]["img_entire"]["reference"]
+        golden_name = str(self.ldb_test_doc["results"]["img_entire"]["reference"]) + ".png"
+        golden_pic = self.ldb_test_doc["results"]["img_entire"]["reference"]
         data_golden = fs.get(ObjectId(str(golden_pic))).read()
         with open(golden_name, 'wb') as f:
             f.write(data_golden)
 
         tiles = []
-        for i, item in enumerate(result_doc["results"]["img_tile"]):
+        for i, item in enumerate(self.ldb_test_doc["results"]["img_tile"]):
             tiles.append({})
-            tiles[i]["name"] = str(result_doc["results"]["img_tile"][item]) + ".png"
-            tiles[i]["pic"] = result_doc["results"]["img_tile"][item]
+            tiles[i]["name"] = str(self.ldb_test_doc["results"]["img_tile"][item]) + ".png"
+            tiles[i]["pic"] = self.ldb_test_doc["results"]["img_tile"][item]
             tiles[i]["data"] = fs.get(ObjectId(str(tiles[i]["pic"]))).read()
             with open(tiles[i]["name"], 'wb') as f:
                 f.write(tiles[i]["data"])
@@ -964,67 +1084,63 @@ class QCResultUploader(PDInterface.PDInterface):
 
     #######################
     ## for Mass measurement
-    def __createMassTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
-        json["properties"]["ACCURACY"] = float('{:.3g}'.format(float(result_doc["results"]["property"]["Scale_accuracy"])))
-        json["results"]["MASS"] = float('{:.3g}'.format(float(result_doc["results"]["mass_value"])))
-        json["comments"] = [result_doc["results"]["comment"]]
+    def __createMassTestRun(self, json, timestampAsString):
+        json["properties"]["ACCURACY"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["property"]["Scale_accuracy"])))
+        json["results"]["MASS"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["mass_value"])))
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ################
     ## for Metrology
-    def __createMetrologyTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
-        json["results"]["DISTANCE_TOP"]    = float('{:.3g}'.format(float(result_doc["results"]["distance top"])))
-        json["results"]["DISTANCE_LEFT"]   = float('{:.3g}'.format(float(result_doc["results"]["distance left"])))
-        json["results"]["DISTANCE_RIGHT"]  = float('{:.3g}'.format(float(result_doc["results"]["distance right"])))
-        json["results"]["DISTANCE_BOTTOM"] = float('{:.3g}'.format(float(result_doc["results"]["distance bottom"])))
+    def __createMetrologyTestRun(self, json, timestampAsString):
+        json["results"]["DISTANCE_TOP"]    = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["distance top"])))
+        json["results"]["DISTANCE_LEFT"]   = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["distance left"])))
+        json["results"]["DISTANCE_RIGHT"]  = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["distance right"])))
+        json["results"]["DISTANCE_BOTTOM"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["distance bottom"])))
 
         json["results"]["ANGLE_OF_BARE_VS_FLEX"] = [
-          float('{:.3g}'.format(float(result_doc["results"]["angle top-left"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["angle top-right"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["angle bottom-left"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["angle bottom-right"])))
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["angle top-left"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["angle top-right"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["angle bottom-left"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["angle bottom-right"])))
         ]
 
         json["results"]["MODULE_THICKNESS_PICKUP_AREA"] = [
-          float('{:.3g}'.format(float(result_doc["results"]["module thickness pickup area chip1"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["module thickness pickup area chip2"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["module thickness pickup area chip3"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["module thickness pickup area chip4"])))
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness pickup area chip1"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness pickup area chip2"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness pickup area chip3"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness pickup area chip4"])))
         ]
         try:
             json["results"]["MODULE_THICKNESS_EDGE"] = [
-              float('{:.3g}'.format(float(result_doc["results"]["module thickness edge chip1"]))),
-              float('{:.3g}'.format(float(result_doc["results"]["module thickness edge chip2"]))),
-              float('{:.3g}'.format(float(result_doc["results"]["module thickness edge chip3"]))),
-              float('{:.3g}'.format(float(result_doc["results"]["module thickness edge chip4"])))
+              float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness edge chip1"]))),
+              float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness edge chip2"]))),
+              float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness edge chip3"]))),
+              float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness edge chip4"])))
             ]
         except:
             json["results"]["MODULE_THICKNESS_EDGE"] = [1.0, 1.0, 1.0, 1.0]
 
-        json["results"]["MODULE_THICKNESS_HV_CAPACITOR"] = float('{:.3g}'.format(float(result_doc["results"]["module thickness HV capacitor"])))
-        json["results"]["MODULE_THICKNESS_DATA_CONNECTOR"] = float('{:.3g}'.format(float(result_doc["results"]["module thickness Data connector"])))
+        json["results"]["MODULE_THICKNESS_HV_CAPACITOR"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness HV capacitor"])))
+        json["results"]["MODULE_THICKNESS_DATA_CONNECTOR"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["module thickness Data connector"])))
 
         try:
-            json["results"]["PLANARITY_VACUUM_ON"]  = float('{:.3g}'.format(float(result_doc["results"]["planarity vacuum on"])))
-            json["results"]["PLANARITY_VACUUM_OFF"] = float('{:.3g}'.format(float(result_doc["results"]["planarity vacuum off"])))
-            json["results"]["PLANARITY_VACUUM_ON_STD_DEV"]  = float('{:.3g}'.format(float(result_doc["results"]["planarity vacuum on std dev"])))
-            json["results"]["PLANARITY_VACUUM_OFF_STD_DEV"] = float('{:.3g}'.format(float(result_doc["results"]["planarity vacuum off std dev"])))
+            json["results"]["PLANARITY_VACUUM_ON"]  = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["planarity vacuum on"])))
+            json["results"]["PLANARITY_VACUUM_OFF"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["planarity vacuum off"])))
+            json["results"]["PLANARITY_VACUUM_ON_STD_DEV"]  = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["planarity vacuum on std dev"])))
+            json["results"]["PLANARITY_VACUUM_OFF_STD_DEV"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["planarity vacuum off std dev"])))
         except:
             json["results"]["PLANARITY_VACUUM_ON"]  = 1.0
             json["results"]["PLANARITY_VACUUM_OFF"] = 1.0
             json["results"]["PLANARITY_VACUUM_ON_STD_DEV"]  = 1.0
             json["results"]["PLANARITY_VACUUM_OFF_STD_DEV"] = 1.0
 
-        json["comments"] = [result_doc["results"]["comment"], "No results about Thickness Edge and Planarity Vacuum on/off"]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"], "No results about Thickness Edge and Planarity Vacuum on/off"]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
-
-    def __createMetrologyQuadTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
+        return json
 
+    def __createMetrologyQuadTestRun(self, json, timestampAsString):
         json["results"]["DISTANCE_TOP"] = ""
         json["results"]["Z_AVERAGE"] = ""
         json["results"]["DISTANCE_LEFT"] = ""
@@ -1039,13 +1155,11 @@ class QCResultUploader(PDInterface.PDInterface):
         json["results"]["THICKNESS_LEFT_EDGE"] = ""
         json["results"]["THICKNESS_RIGHT_EDGE"] = ""
 
-        json["comments"] = [result_doc["results"]["comment"]]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
-
-    def __createMetrologyTripletTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
+        return json
 
+    def __createMetrologyTripletTestRun(self, json, timestampAsString):
         json["results"]["DISPLACEMENT_X"] = []
         json["results"]["DISPLACEMENT_Y"] = []
         json["results"]["THICKNESS_GLUE"] = []
@@ -1058,36 +1172,33 @@ class QCResultUploader(PDInterface.PDInterface):
         json["results"]["THICKNESS_GLUE_STD_DEV"] = []
         json["results"]["FLATNESS"] = []
 
-        json["comments"] = [result_doc["results"]["comment"]]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ##################
     ## for coplanarity
-    def __createCoplanarityTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
-
+    def __createCoplanarityTestRun(self, json, timestampAsString):
         json["results"]["ANGLE"] = [
-          float('{:.3g}'.format(float(result_doc["results"]["angle alpha"]))),
-          float('{:.3g}'.format(float(result_doc["results"]["angle beta"])))
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["angle alpha"]))),
+          float('{:.3g}'.format(float(self.ldb_test_doc["results"]["angle beta"])))
         ]
-        json["results"]["BACKSIDE_COPLANARITY"] = float('{:.3g}'.format(float(result_doc["results"]["coplanarity"])))
+        json["results"]["BACKSIDE_COPLANARITY"] = float('{:.3g}'.format(float(self.ldb_test_doc["results"]["coplanarity"])))
 
-        json["comments"] = [result_doc["results"]["comment"]]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ################
     ## for Sensor IV
-    def __createSensorIVTestRun(self, result_doc, module_doc, str_date, test_item):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
+    def __createSensorIVTestRun(self, json, timestampAsString):
         json["results"]["TIME"] = []
         json["results"]["CURRENT_MEAN"] = []
         json["results"]["CURRENT_SIGMA"] = []
         json["results"]["VOLTAGE"] = []
         json["results"]["HUMIDITY"] = []
         json["results"]["TEMPERATURE"] = []
-        for items in result_doc["results"]["Sensor_IV"]:
+        for items in self.ldb_test_doc["results"]["Sensor_IV"]:
             json["results"]["TIME"].append(float('{:.3g}'.format(items["Time"])))
             json["results"]["CURRENT_MEAN"].append(float('{:.3g}'.format(items["Current_mean"])))
             json["results"]["CURRENT_SIGMA"].append(float('{:.3g}'.format(items["Current_sigma"])))
@@ -1096,29 +1207,21 @@ class QCResultUploader(PDInterface.PDInterface):
                 json["results"]["HUMIDITY"].append(float('{:.3g}'.format(items["Humidity"])))
             if "Temperature" in items:
                 json["results"]["TEMPERATURE"].append(float('{:.3g}'.format(items["Temperature"])))
-        json["comments"] = [result_doc["results"]["comment"]]
-        if test_item == "SENSOR_IV_30_DEGREE":
-            json["properties"]["ENVIRONMENT_TEMPERATURE"] = 30
-        elif test_item == "SENSOR_IV_20_DEGREE":
-            json["properties"]["ENVIRONMENT_TEMPERATURE"] = 20
-        elif test_item == "SENSOR_IV_min15_DEGREE":
-            json["properties"]["ENVIRONMENT_TEMPERATURE"] = -15
-        else:
-            json["properties"]["ENVIRONMENT_TEMPERATURE"] = 99999
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
+        json["properties"]["ENVIRONMENT_TEMPERATURE"] = self.testSetTemp
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ##############
     ## for SLDO VI
-    def __createSLDOVITestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
+    def __createSLDOVITestRun(self, json, timestampAsString):
         json["results"]["TIME"] = []
         json["results"]["CURRENT"] = []
         json["results"]["VOLTAGE_MEAN"] = []
         json["results"]["VOLTAGE_SIGMA"] = []
         json["results"]["HUMIDITY"] = []
         json["results"]["TEMPERATURE"] = []
-        for items in result_doc["results"]["SLDO_VI"]:
+        for items in self.ldb_test_doc["results"]["SLDO_VI"]:
             json["results"]["TIME"].append(float('{:.3g}'.format(items["Time"])))
             json["results"]["CURRENT"].append(float('{:.3g}'.format(items["Current"])))
             json["results"]["VOLTAGE_MEAN"].append(float('{:.3g}'.format(items["Voltage_mean"])))
@@ -1127,124 +1230,113 @@ class QCResultUploader(PDInterface.PDInterface):
                 json["results"]["HUMIDITY"].append(float('{:.3g}'.format(items["Humidity"])))
             if "Temperature" in items:
                 json["results"]["TEMPERATURE"].append(float('{:.3g}'.format(items["Temperature"])))
-        json["comments"] = [result_doc["results"]["comment"]]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ################################
     ## for Glue module + flex attach
-    def __createGlueTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
-        json["properties"]["GLUE_TYPE"] = result_doc["results"]["property"]["Glue_name"]
-        Main_A = result_doc["results"]["property"]["Volume_ratio_of_glue_mixture"].split(":")[1].split(",")[0]
-        Sub_B = result_doc["results"]["property"]["Volume_ratio_of_glue_mixture"].split(":")[2]
+    def __createGlueTestRun(self, json, timestampAsString):
+        json["properties"]["GLUE_TYPE"] = self.ldb_test_doc["results"]["property"]["Glue_name"]
+        Main_A = self.ldb_test_doc["results"]["property"]["Volume_ratio_of_glue_mixture"].split(":")[1].split(",")[0]
+        Sub_B = self.ldb_test_doc["results"]["property"]["Volume_ratio_of_glue_mixture"].split(":")[2]
         json["properties"]["RATIO"] = float(Main_A)/float(Sub_B)
-        json["properties"]["NAME"] = result_doc["user"]
-        json["properties"]["BATCH_NUMBER"] = result_doc["results"]["property"]["Glue_batch_number"]
-        json["results"]["TEMP"] = result_doc["results"]["Room_temperature"]
-        json["results"]["HUMIDITY"] = result_doc["results"]["Humidity"]
-        json["comments"] = [result_doc["results"]["comment"]]
+        json["properties"]["NAME"] = self.ldb_test_doc["user"]
+        json["properties"]["BATCH_NUMBER"] = self.ldb_test_doc["results"]["property"]["Glue_batch_number"]
+        json["results"]["TEMP"] = self.ldb_test_doc["results"]["Room_temperature"]
+        json["results"]["HUMIDITY"] = self.ldb_test_doc["results"]["Humidity"]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ##################
     ## for Wirebonding
-    def __createWirebondingTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
-        json["properties"]["MACHINE"] = result_doc["results"]["property"]["Machine"]
-        json["properties"]["OPERATOR"] = result_doc["results"]["property"]["Operator_name"]
-        json["properties"]["BOND_WIRE_BATCH"] = result_doc["results"]["property"]["Bond_wire_batch"]
-        if result_doc["results"]["property"]["Bond_program"] != '':
+    def __createWirebondingTestRun(self, json, timestampAsString):
+        json["properties"]["MACHINE"] = self.ldb_test_doc["results"]["property"]["Machine"]
+        json["properties"]["OPERATOR"] = self.ldb_test_doc["results"]["property"]["Operator_name"]
+        json["properties"]["BOND_WIRE_BATCH"] = self.ldb_test_doc["results"]["property"]["Bond_wire_batch"]
+        if self.ldb_test_doc["results"]["property"]["Bond_program"] != '':
             json["properties"]["BOND_PROGRAM"] = "Attached Bond Program"
         else:
             json["properties"]["BOND_PROGRAM"] = "No Bond Program"
-        json["properties"]["BONDING_JIG"] = result_doc["results"]["property"]["Bonding_jig"]
-        json["results"]["TEMPERATURE"] = result_doc["results"]["Temperature"]
-        json["results"]["HUMIDITY"] = result_doc["results"]["Humidity"]
-        json["comments"] = [result_doc["results"]["comment"]]
+        json["properties"]["BONDING_JIG"] = self.ldb_test_doc["results"]["property"]["Bonding_jig"]
+        json["results"]["TEMPERATURE"] = self.ldb_test_doc["results"]["Temperature"]
+        json["results"]["HUMIDITY"] = self.ldb_test_doc["results"]["Humidity"]
+        json["comments"] = [self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ###############
     ## for Wirebond
-    def __createWirebondTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
+    def __createWirebondTestRun(self, json, timestampAsString):
         json["properties"]["MACHINE"] = "No result"
         json["properties"]["SPEED"] = 0
         json["properties"]["SHEAR"] = 0
         json["properties"]["LOAD"] = 0
         json["properties"]["OPERATOR"] = "No result"
-        json["results"]["MIN_LOAD"] = result_doc["results"]["minimum_load"]
-        json["results"]["MAX_LOAD"] = result_doc["results"]["maximum_load"]
-        json["results"]["MEAN_LOAD"] = result_doc["results"]["mean_load"]
-        json["results"]["STD_DEV_LOAD"] = result_doc["results"]["load_standard_deviation"]
-        json["results"]["PERCENT_HEEL_BREAKS"] = result_doc["results"]["percentage_of_heel_breaks"]
-        json["comments"] = ["No properties for this test run" , result_doc["results"]["comment"]]
+        json["results"]["MIN_LOAD"] = self.ldb_test_doc["results"]["minimum_load"]
+        json["results"]["MAX_LOAD"] = self.ldb_test_doc["results"]["maximum_load"]
+        json["results"]["MEAN_LOAD"] = self.ldb_test_doc["results"]["mean_load"]
+        json["results"]["STD_DEV_LOAD"] = self.ldb_test_doc["results"]["load_standard_deviation"]
+        json["results"]["PERCENT_HEEL_BREAKS"] = self.ldb_test_doc["results"]["percentage_of_heel_breaks"]
+        json["comments"] = ["No properties for this test run" , self.ldb_test_doc["results"]["comment"]]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     #####################
     ## for Parylene info.
-    def __createParyleneTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"],str_date)
+    def __createParyleneTestRun(self, json, timestampAsString):
+        json["properties"]["BATCH_NUMBER"] = self.ldb_test_doc["results"]["property"]["Parylene_Batch_Number"]
+        json["properties"]["PARYLENE_TYPE"] = self.ldb_test_doc["results"]["property"]["Parylene_Type"]
+        json["properties"]["MASKING_OPERATOR"] = self.ldb_test_doc["results"]["property"]["Institution_of_Masking_Operator"]
+        json["propertie"]["REMOVING_MASK_OPERATOR"] = self.ldb_test_doc["results"]["property"]["Institution_of_Operator_Removing_Mask"]
 
-        json["properties"]["BATCH_NUMBER"] = result_doc["results"]["property"]["Parylene_Batch_Number"]
-        json["properties"]["PARYLENE_TYPE"] = result_doc["results"]["property"]["Parylene_Type"]
-        json["properties"]["MASKING_OPERATOR"] = result_doc["results"]["property"]["Institution_of_Masking_Operator"]
-        json["propertie"]["REMOVING_MASK_OPERATOR"] = result_doc["results"]["property"]["Institution_of_Operator_Removing_Mask"]
+        json["results"]["THICKNESS"] = self.ldb_test_doc["results"]["Parylene_thickness_measured_by_vendor"]
+        json["results"]["THICKNESS_ITK"] = self.ldb_test_doc["results"]["Parylene_thickness_measured_by_ITk_Institute"]
 
-        json["results"]["THICKNESS"] = result_doc["results"]["Parylene_thickness_measured_by_vendor"]
-        json["results"]["THICKNESS_ITK"] = result_doc["results"]["Parylene_thickness_measured_by_ITk_Institute"]
-
-        return self.pd_client.post("uploadTestRunResults", json=json)
+        return json
 
     #####################
     ### for Thermal Cycle
-    def __createThermalTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"], str_date)
-
-        json["properties"]["MACHINE"] = result_doc["results"]["property"]["Machine"]
-        json["properties"]["MIN_TEMP"] = result_doc["results"]["property"]["Temp_min_value"]
-        json["properties"]["MAX_TEMP"] = result_doc["results"]["property"]["Temp_max_value"]
-        json["properties"]["NUM_CYCLES"] = result_doc["results"]["property"]["N_cycle"]
-        json["properties"]["CYCLING_SPEED"] = result_doc["results"]["property"]["Cycle_speed_value"]
+    def __createThermalTestRun(self, json, timestampAsString):
+        json["properties"]["MACHINE"] = self.ldb_test_doc["results"]["property"]["Machine"]
+        json["properties"]["MIN_TEMP"] = self.ldb_test_doc["results"]["property"]["Temp_min_value"]
+        json["properties"]["MAX_TEMP"] = self.ldb_test_doc["results"]["property"]["Temp_max_value"]
+        json["properties"]["NUM_CYCLES"] = self.ldb_test_doc["results"]["property"]["N_cycle"]
+        json["properties"]["CYCLING_SPEED"] = self.ldb_test_doc["results"]["property"]["Cycle_speed_value"]
 
-        return self.pd_client.post("uploadTestRunResults",json=json)
+        return json
 
     ######################
     ## for ADC calibration
-    def __createADCcalibrationTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"],str_date)
-        json["results"]["FLAG"] = eval(result_doc["results"]["flag"])
+    def __createADCcalibrationTestRun(self, json, timestampAsString):
+        json["results"]["FLAG"] = eval(self.ldb_test_doc["results"]["flag"])
 
-        return self.pd_client.post("uploadTestRunResults", json=json)
+        return json
 
     #############
     ## for Tuning
-    def __createTuningTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"],str_date)
-        json["results"]["FLAG"] = eval(result_doc["results"]["flag"])
+    def __createTuningTestRun(self, json, timestampAsString):
+        json["results"]["FLAG"] = eval(self.ldb_test_doc["results"]["flag"])
 
-        return self.pd_client.post("uploadTestRunResults", json=json)
+        return json
 
     #############
     ## for WP envelope metrology
-    def __createWPenvelopeTestRun(self, result_doc, module_doc, str_date):
-        json = self.__createTestTemplate(module_doc, result_doc["testType"],str_date)
-
+    def __createWPenvelopeTestRun(self, json, timestampAsString):
         json["results"]["DISTANCE_X"] = []
         json["results"]["DISTANCE_Y"] = []
         json["results"]["THICKNESS_MEAN"] = []
         json["results"]["THICKNESS_STDDEV"] = []
 
-        return self.pd_client.post("uploadTestRunResults", json=json)
+        return json
 
     #################
     ## for electrical
-    def __getElecTestAnalysisResult(self, result_doc, chip_name):
+    def __getElecTestAnalysisResult(self, localdb_test_doc, chip_name):
         dict_ = {}
-        if "analysis" in result_doc["results"]:
-            for analysis in result_doc["results"]["analysis"]:
+        if "analysis" in self.ldb_test_doc["results"]:
+            for analysis in self.ldb_test_doc["results"]["analysis"]:
                 if analysis["name"] == "bad_pixel_analysis":
                     for chip_result in analysis["result"]:
                         if chip_result["chip"] == chip_name:
@@ -1252,22 +1344,7 @@ class QCResultUploader(PDInterface.PDInterface):
                                 dict_[criteria["criteria"].upper()] = criteria["num"]
         return dict_
 
-    def __getElecTestSettingTemp(self, result_doc, test_item):
-        temp = result_doc["results"]["setting_temp"]
-        try:
-            temp = int(temp)
-        except:
-            if test_item == "READOUT_IN_BASIC_ELECTRICAL_TEST_30_DEGREE" or "PIXEL_FAILURE_TEST_30_DEGREE":
-                temp = 30
-            elif test_item == "READOUT_IN_BASIC_ELECTRICAL_TEST_20_DEGREE" or "PIXEL_FAILURE_TEST_20_DEGREE":
-                temp = 20
-            elif test_item == "READOUT_IN_BASIC_ELECTRICAL_TEST_min15_DEGREE" or "PIXEL_FAILURE_TEST_min15_DEGREE":
-                temp = -15
-            else:
-                temp = 99999
-        return temp
-
-    def __createElecTestTemplate(self, doc, testType, str_date):
+    def __createElecTestTemplate(self, doc, testType, timestampAsString):
         project = {"project": doc["project"]["code"]}
         componentType = {"componentType": doc["componentType"]["code"]}
         pd_testType = {"code": testType}
@@ -1278,15 +1355,16 @@ class QCResultUploader(PDInterface.PDInterface):
           **test_template,
           "component": doc["serialNumber"],
           "institution": doc["currentLocation"]["code"],
-          "date": str_date,
+          "date": timestampAsString,
           "properties":{},
           "results":{}
         }
         return json
 
-    def __createElecTestRunForModule(self, result_doc, module_doc, str_date, cp_test_map, test_item):
-        json = self.__createElecTestTemplate(module_doc, result_doc["testType"], str_date)
-        json["properties"] = {"ENVIRONMENT_TEMPERATURE":self.__getElecTestSettingTemp(result_doc, test_item)}
+    def __createElecTestRunForModule(self, timestampAsString, cp_test_map, test_item):
+        json = self.__createElecTestTemplate(self.pdb_component_doc, self.testType, timestampAsString)
+        json["properties"] = {"ENVIRONMENT_TEMPERATURE":self.testSetTemp}
+        json["runNumber"] = str( self.ldb_test_doc["_id"] )
         json["results"]["RESULT_IDS"] = [v for i,v in cp_test_map.items()]
         json["results"]["DIGITAL_DEAD"] = []
         json["results"]["DIGITAL_BAD"] = []
@@ -1297,25 +1375,31 @@ class QCResultUploader(PDInterface.PDInterface):
         json["results"]["TUNING_BAD_TOT"] = []
         json["results"]["HIGH_ENC"] = []
         json["results"]["NOISY"] = []
-        for chip in result_doc["results"]["analysis"][0]["result"]:
-            for values in chip["result"]:
-                if values["criteria"] == "digital_dead": json["results"]["DIGITAL_DEAD"].append(values["num"])
-                if values["criteria"] == "digital_bad": json["results"]["DIGITAL_BAD"].append(values["num"])
-                if values["criteria"] == "analog_dead": json["results"]["ANALOG_DEAD"].append(values["num"])
-                if values["criteria"] == "analog_bad": json["results"]["ANALOG_BAD"].append(values["num"])
-                if values["criteria"] == "tuning_failed": json["results"]["TUNING_FAILED"].append(values["num"])
-                if values["criteria"] == "tuning_bad_threshold": json["results"]["TUNING_BAD_THRESHOLD"].append(values["num"])
-                if values["criteria"] == "tuning_bad_tot": json["results"]["TUNING_BAD_TOT"].append(values["num"])
-                if values["criteria"] == "high_enc": json["results"]["HIGH_ENC"].append(values["num"])
-                if values["criteria"] == "noisy": json["results"]["NOISY"].append(values["num"])
+        
+        try:
+            for chip in self.ldb_test_doc["results"]["analysis"][0]["result"]:
+                logger.info( 'createElecTestRunForModule(): chip = {}'.format( chip ) ) 
+                for values in chip["result"]:
+                    if values["criteria"] == "digital_dead": json["results"]["DIGITAL_DEAD"].append(values["num"])
+                    if values["criteria"] == "digital_bad": json["results"]["DIGITAL_BAD"].append(values["num"])
+                    if values["criteria"] == "analog_dead": json["results"]["ANALOG_DEAD"].append(values["num"])
+                    if values["criteria"] == "analog_bad": json["results"]["ANALOG_BAD"].append(values["num"])
+                    if values["criteria"] == "tuning_failed": json["results"]["TUNING_FAILED"].append(values["num"])
+                    if values["criteria"] == "tuning_bad_threshold": json["results"]["TUNING_BAD_THRESHOLD"].append(values["num"])
+                    if values["criteria"] == "tuning_bad_tot": json["results"]["TUNING_BAD_TOT"].append(values["num"])
+                    if values["criteria"] == "high_enc": json["results"]["HIGH_ENC"].append(values["num"])
+                    if values["criteria"] == "noisy": json["results"]["NOISY"].append(values["num"])
+        except Exception as e:
+            logger.warning( '{}'.format( e ) )
 
         return self.pd_client.post("uploadTestRunResults",json=json)
 
-    def __createElecTestRunForFEChip(self, result_doc, chip_name, str_date):
+    def __createElecTestRunForFEChip(self, chip_name, timestampAsString):
         child_doc = super().getCompFromProdDB(chip_name)
-        json = self.__createElecTestTemplate(child_doc, result_doc["testType"], str_date)
-        json["properties"] = {"QC_STAGE":result_doc["currentStage"]}
-        json["results"] = self.__getElecTestAnalysisResult(result_doc, chip_name)
+        json = self.__createElecTestTemplate(child_doc, self.testType, timestampAsString)
+        json["properties"] = {"QC_STAGE":self.ldb_test_doc["currentStage"]}
+        json["results"] = self.__getElecTestAnalysisResult(self.ldb_test_doc, chip_name)
+        json["runNumber"] = str( self.ldb_test_doc["_id"] ):
 
         return self.pd_client.post( "uploadTestRunResults", json=json)
 
@@ -1328,15 +1412,15 @@ class QCResultUploader(PDInterface.PDInterface):
         return
 
     def __attachFileToComp(self, filepath, filename, module_doc):
-        for attachment in module_doc["attachments"]:
+        for attachment in self.pdb_component_doc["attachments"]:
             if attachment["filename"] == filename:
-                self.pd_client.post( "deleteComponentAttachment", json = {"component":module_doc["serialNumber"], "code": attachment["code"]} )
+                self.pd_client.post( "deleteComponentAttachment", json = {"component":self.pdb_component_doc["serialNumber"], "code": attachment["code"]} )
                 logger.info("Delete an old config for the module page: " + filename)
         with open(filepath, "rb") as f:
             upload_file = f
             upload_filetype = filename.split(".")[-1]
             page_attachment = { "data": (filename, upload_file, upload_filetype)}
-            self.pd_client.post( "createComponentAttachment", data=dict( component=module_doc["serialNumber"], type="file" ), files=page_attachment )
+            self.pd_client.post( "createComponentAttachment", data=dict( component=self.pdb_component_doc["serialNumber"], type="file" ), files=page_attachment )
             logger.info("Attach a new config for the module page: " + filename)
         return
 
@@ -1355,7 +1439,7 @@ class QCResultUploader(PDInterface.PDInterface):
             n = i + 1
             json_name = "json" + str(n)
             json_name = {
-                "component": module_doc["serialNumber"],
+                "component": self.pdb_component_doc["serialNumber"],
                 "code": "RD53A_PULL-UP_RESISTOR" + str(n),
                 "value": prop_doc["results"]["value"]["chip"+str(n)]
             }
@@ -1370,7 +1454,7 @@ class QCResultUploader(PDInterface.PDInterface):
             n = i + 1
             json_name = "json" + str(n)
             json_name = {
-                "component": module_doc["serialNumber"],
+                "component": self.pdb_component_doc["serialNumber"],
                 "code": "IREFTRIM_FE" + str(n),
                 "value": prop_doc["results"]["value"]["chip"+str(n)]
             }
@@ -1382,7 +1466,7 @@ class QCResultUploader(PDInterface.PDInterface):
     ## for Orientation registor
     def __createOrientationTestRun(self, prop_doc, module_doc):
         json_name = {
-            "component": module_doc["serialNumber"],
+            "component": self.pdb_component_doc["serialNumber"],
             "code": "ORIENTATION",
             "value": prop_doc["results"]["orientation"]
         }
@@ -1403,13 +1487,13 @@ class QCResultUploader(PDInterface.PDInterface):
         attachment_file = open(prop_doc["testType"] + '_detail.json', 'rb')
         page_attachment = {"data": (prop_doc["testType"] + '_detail.json', attachment_file, "json")}
 
-        self.pd_client.post( "createComponentAttachment", data=dict( component=module_doc["serialNumber"], type="file" ), files=page_attachment )
+        self.pd_client.post( "createComponentAttachment", data=dict( component=self.pdb_component_doc["serialNumber"], type="file" ), files=page_attachment )
         return  os.remove(prop_doc["testType"] + '_detail.json')
 
     def __deletePropertyAttachment(self, module_doc):
-        for item in module_doc["attachments"]:
+        for item in self.pdb_component_doc["attachments"]:
             if "detail.json" in item["filename"]:
-                self.pd_client.post("deleteComponentAttachment", json={"component": module_doc["code"], "code": item["code"]} )
+                self.pd_client.post("deleteComponentAttachment", json={"component": self.pdb_component_doc["code"], "code": item["code"]} )
 
         return
 
@@ -1417,7 +1501,7 @@ class QCResultUploader(PDInterface.PDInterface):
     ## set stage of ITkPD ##
     def __setStage(self, module_doc, module_QC_info):
         nextStage = module_QC_info["currentStage"]
-        json_stage = {"component": module_doc["serialNumber"], "stage": nextStage}
+        json_stage = {"component": self.pdb_component_doc["serialNumber"], "stage": nextStage}
 
         return self.pd_client.post("setComponentStage", json=json_stage )
 
@@ -1431,21 +1515,21 @@ class QCResultUploader(PDInterface.PDInterface):
         except:
             pass
         os.mkdir(cache_dir)
-        old_result_doc = {}
+        previous_ldb_test_doc = {}
         for attachment in tr_doc["attachments"]:
             jfile = self.pd_client.get("uu-app-binarystore/getBinaryData",json={"code": attachment["code"]}).content
             if "_results.json" in attachment["filename"]:
                 with open(os.path.join(cache_dir,"{}".format(attachment["filename"])),"wb") as f:
                     f.write(jfile)
                 with open(os.path.join(cache_dir,"{}".format(attachment["filename"])),"r") as f:
-                    old_result_doc["0"] = json.load(f)
+                    previous_ldb_test_doc["0"] = json.load(f)
 
-        return old_result_doc
+        return previous_ldb_test_doc
 
-#    def __deleteResult(self, tr_doc, new_result_id, old_result_doc):
+#    def __deleteResult(self, tr_doc, new_result_id, previous_ldb_test_doc):
 #        cache_dir = "{}/attachments".format(".")
 #        attachment_file = open('attachments/' + "delete.json", 'rb')
-#        page_attachment = {"data": (old_result_doc["0"]["testType"] + "_deletedResults.json", attachment_file, "json")}
+#        page_attachment = {"data": (previous_ldb_test_doc["0"]["testType"] + "_deletedResults.json", attachment_file, "json")}
 #        attach_ins = self.pd_client.post("createTestRunAttachment", data=dict( testRun=new_result_id, type="file" ), files=page_attachment )
 #
 #        self.pd_client.post("deleteTestRun", json={"testRun": tr_doc["id"]})
@@ -1455,76 +1539,224 @@ class QCResultUploader(PDInterface.PDInterface):
 
 ###################
 ## main function ##
-    def upload_results(self, msn):
+    def upload_results(self, componentSerialNumber):
+        
+        self.componentSerialNumber     = componentSerialNumber
+        
         if not os.path.exists(IF_DIR):
             os.makedirs(IF_DIR)
-        do_filepath = IF_DIR + "/doing_upload_" + msn + ".txt"
-        with open(do_filepath, "w") as f:
+        doFilePath = IF_DIR + "/doing_upload_" + componentSerialNumber + ".txt"
+        with open(doFilePath, "w") as f:
             f.write("doing now")
 
-        if os.path.exists(IF_DIR + '/doing_upload_' + msn + '_fail' + '.txt'):
-            os.remove(IF_DIR + '/doing_upload_' + msn + '_fail' + '.txt')
+        if os.path.exists(IF_DIR + '/doing_upload_' + componentSerialNumber + '_fail' + '.txt'):
+            os.remove(IF_DIR + '/doing_upload_' + componentSerialNumber + '_fail' + '.txt')
+        
+        logger.info("Module name: " + componentSerialNumber)
+        
+        
+        self.doUploadFuncs = { "module":
+                               {
+                                   "ADC_CALIBRATION"                  : self.__createADCcalibrationTestRun,
+                                   "FLATNESS"                         : self.__createCoplanarityTestRun,
+                                   "READOUT_IN_BASIC_ELECTRICAL_TEST" : self.__create_electrial_pdb,
+                                   "GLUE_MODULE_FLEX_ATTACH"          : self.__createGlueTestRun,
+                                   "MASS"                             : self.__createMassTestRun,
+                                   "METROLOGY"                        : self.__createMetrologyTestRun,
+                                   "OPTICAL"                          : self.__createOpticalTestRun,
+                                   "PARYLENE"                         : self.__createParyleneTestRun,
+                                   "SLDO_VI"                          : self.__createSLDOVITestRun,
+                                   "SENSOR_IV"                        : self.__createSensorIVTestRun,
+                                   "THERMALCYCLE"                     : self.__createThermalTestRun,
+                                   "TUNING"                           : self.__createTuningTestRun,
+                                   "WP_ENVELOPE"                      : self.__createWPenvelopeTestRun,
+                                   "WIREBOND"                         : self.__createWirebondTestRun,
+                                   "WIREBONDING"                      : self.__createWirebondingTestRun
+                               }
+                           }
+        
+        
+        #----------------------------------------------------------------------------------------------
+        # Collect informations from LocalDB
+        # Hereafter, LocalDB variables start from prefix "ldb_"
+        
+        self.ldb_component             = super().getCompFromLocalDB(componentSerialNumber)
+        self.ldb_componentId           = str( self.ldb_component["_id"] )
+        self.ldb_componentType         = self.ldb_component["componentType"]
+        self.ldb_component_QC_info     = super().getQmsFromLocalDB(self.ldb_componentId)
+        self.ldb_component_prop_info   = super().getPmsFromLocalDB(self.ldb_componentId)
+        
+        if not self.ldb_componentType in self.doUploadFuncs:
+            logger.error( 'Component type "{}" is not supported yet.'.format( self.ldb_componentType ) )
+            return
+        
+        stageFlow = [item for item in self.ldb_component_QC_info["QC_results"] ]
+        
+        print( super().getCompFromLocalDB(componentSerialNumber) )
+        #print( '\n\n\n\n' )
+        #pprint.pprint( 'self.ldb_component_QC_info: ' )
+        #pprint.pprint( self.ldb_component_QC_info )
+        
+        try:
+            self.ldb_upload_status = self.ldb_component_QC_info["upload_status"]
+        except:
+            self.ldb_upload_status = {}
+            for stage in self.ldb_component_QC_info["stage_flow"]:
+                self.ldb_upload_status[stage] = "-1"
+            localdb.QC.module.status.update_one( {"_id": ObjectId(str(self.ldb_component_QC_info["_id"]))}, {"$set": {"upload_status": self.ldb_upload_status }} )
+            
+        
+        #pprint.pprint( 'self.ldb_upload_status: ')
+        #pprint.pprint( self.ldb_upload_status )
+        
+        
+        # Include up to the previous stage wrt the currentStage as a transaction stage
+        transactionStages = []
+        for stage in stageFlow:
+            if stage == self.ldb_component_QC_info["currentStage"]:
+                break
+            transactionStages.append(stage)
+            
+        #print( '\n\n\n\n' )
+        logger.info('Transaction Stages: {}'.format( transactionStages ) )
+        
+        #----------------------------------------------------------------------------------------------
+        # Collect ProdDB Component and TestRun docs
+        # Hereafter, LocalDB variables start from prefix "pdb_"
+        
+        self.pdb_component_doc        = super().getCompFromProdDB(componentSerialNumber)
+        self.pdb_prev_testRuns        = [test for test in self.pd_client.get("listTestRunsByComponent", json={"component": self.pdb_component_doc["code"] }) ]
+        
+        #print( '\n\n\n\n' )
+        #pprint.pprint('self.pdb_prev_testRuns:')
+        #pprint.pprint( self.pdb_prev_testRuns )
+        
+        
+        #----------------------------------------------------------------------------------------------
+        # Loop over stages
+        
+        for stage in transactionStages:
+            
+            self.stage = stage
+            
+            isAtLeastOneTestUploaded = False
+            
+            # Loop over tests of the stage
+            for testType, result_id in self.ldb_component_QC_info["QC_results"][stage].items():
+                
+                # If the result is blank, skip
+                if result_id == "-1": continue
+                
+                logger.info("Test : {}.{}".format( stage, testType ) )
+                
+                self.ldb_test_doc = super().getQrFromLocalDB(result_id)
+                
+                #pprint.pprint( 'self.ldb_test_doc:' )
+                #pprint.pprint( self.ldb_test_doc )
+                
+                self.testSetTemp = -9999
+                if testType.find("30DEG") >=0 or testType.find("30_DEG") >= 0:
+                    self.testSetTemp = 30
+                elif testType.find("20DEG") >=0 or testType.find("20_DEG") >= 0:
+                    self.testSetTemp = 20
+                if testType.find("MINUS15DEG") >=0 or testType.find("min15_DEG") >= 0:
+                    self.testSetTemp = -15
+                
+                self.testType = testType.replace("_30DEG", "").replace("_20DEG", "").replace("_MINUS15DEG", "")
+                
+                self.isExclusiveTest = ( self.testType == testType )
+                
+                testSpecificCallback = None
+                try:
+                    
+                    testSpecificCallback = self.doUploadFuncs[ self.ldb_componentType ][ self.testType ]
+                    
+                except Exception as e:
+                    logger.error( 'Error in self.doUploadFuncs[ self.testType ] ()' )
+                    logger.error( 'self.ldb_componentType = {}'.format( self.ldb_componentType ) )
+                    logger.error( 'testType = {}'.format( self.testType ) )
+                    logger.error( '{}'.format( e ) )
+                    
+                # Execute uploading
+                if testSpecificCallback:
+                    
+                    isUploaded = self.__upload( testSpecificCallback )
+                    
+                    if isUploaded:
+                        isAtLeastOneTestUploaded = True
+                    
+                    # Update the QC status in LocalDB
+                    if isUploaded:
+                        localdb.QC.module.status.update_one(
+                            { "_id": self.ldb_component_QC_info["_id"] },
+                            {"$set": {"QC_results_pdb.{}.{}".format( stage, testType ) : self.pdb_testRunId }} )
+                    
+                
+            #endfor testType, result_id in self.ldb_component_QC_info["QC_results"][stage].items()
+            
+            # Sign-off the stage and go to the next stage
+            localdb.QC.module.status.update_one( {"_id": self.ldb_component_QC_info["_id"]}, {"$set": {"upload_status.{}".format(stage): "1" }} )
+            
+            next_stage = stageFlow[ stageFlow.index(stage)+1 ]
+            localdb.QC.module.status.update_one( {"_id": self.ldb_component_QC_info["_id"]}, {"$set": {"currentStage": next_stage}} )
+            localdb.QC.module.status.update_one( {"_id": self.ldb_component_QC_info["_id"]}, {"$set": {"latestSyncedStage": stage}} )
+            
+        # endfor stage in transactionStages
+        
+        if not os.path.exists(IF_DIR + '/doing_upload_' + componentSerialNumber + "_fail" + '.txt'):
+            stage_doc = self.__setStage(self.pdb_component_doc, self.ldb_component_QC_info)
+            logger.info( "Chenged Stage in ITk production DB to " + stage_doc["currentStage"] + "."  )
+        else:
+            logger.info("Not changed Stage in ITk production DB.")
 
-        module_info = super().getCompFromLocalDB(msn)
-        QC_info = localdb.QC.module.status.find_one({"component": str(module_info["_id"])})
-        QC_info["stage_flow"] = [item for item in QC_info["QC_results"]]
-        module_QC_info = super().getQmsFromLocalDB(str(module_info["_id"]))
-        module_prop_info = super().getPmsFromLocalDB(str(module_info["_id"]))
-        logger.info("Module name: " + msn)
-        module_doc = super().getCompFromProdDB(msn)
-        old_test_list = self.pd_client.get("listTestRunsByComponent", json={"component":module_doc["code"]})
-        old_tests = [item for item in old_test_list]
+        logger.info("Finished for all results!!\n")
 
+        os.remove(doFilePath)
         try:
-            upload_status = module_QC_info["upload_status"]
+            shutil.rmtree("{}/attachments".format("."))
         except:
-            upload_status = {}
-            for stage in QC_info["stage_flow"]:
-                upload_status[stage] = "-1"
-            localdb.QC.module.status.update_one( {"_id": ObjectId(str(module_QC_info["_id"]))}, {"$set": {"upload_status": upload_status }} )
-
-        ## Below IF statement will be used for the case you want to procced stage of LDB and PDB at the same time.
-#        if not module_doc["currentStage"]["code"] == module_QC_info["latestSyncedStage"]:
-#            logger.info( "Stage is not corresponded to ITk production DB. Please check it" )
-#        else:
-## get the parent information and setting upload parameter
-        ustages = QC_info["stage_flow"]
-        upload_stage = []
-        for stage in ustages:
-            if stage == module_QC_info["currentStage"]:
-                break
-            upload_stage.append(stage)
+            pass
+
+        if os.path.exists(IF_DIR + '/doing_upload_' + componentSerialNumber + '.txt'):
+            os.remove(IF_DIR + '/doing_upload_' + componentSerialNumber + '.txt')
+        
+        return
 
-        for stage in upload_stage:
+        
+        '''        
+        #----------------------------------------------------------------------------------------------
+        # Loop over stages
+        
+        for stage in transactionStages:
             try:
-                if upload_status[stage] == "-1":
-                    json_stage = {"component": module_doc["serialNumber"], "stage": stage}
+                if self.ldb_upload_status[stage] == "-1":
+                    json_stage = {"component": pdb_component_doc["serialNumber"], "stage": stage}
                     self.pd_client.post("setComponentStage", json=json_stage )
                     logger.info("Stage: " + str(stage))
-                    for test_item, result_id in module_QC_info["QC_results"][stage].items():
+                    for test_item, result_id in self.ldb_component_QC_info["QC_results"][stage].items():
                         logger.info("Test Item: " + str(test_item))
-                        result_doc = super().getQrFromLocalDB(result_id) if result_id != "-1" else {}
-                        result_doc["old_tests"] = old_tests
+                        self.ldb_test_doc = super().getQrFromLocalDB(result_id) if result_id != "-1" else {}
+                        self.ldb_test_doc["pdb_prev_testRuns"] = pdb_prev_testRuns
                         if result_id != "-1":
-                            new_result_id = self.__upload_functions(module_doc, result_doc, test_item, QC_info)
+                            new_result_id = self.__upload_functions(pdb_component_doc, self.ldb_test_doc, test_item, self.ldb_component_QC_info)
 
                     if stage == "MODULEWIREBONDING":
-                        self.__deletePropertyAttachment(module_doc)
-                        for prop_item, prop_id in module_prop_info["QC_properties"].items():
+                        self.__deletePropertyAttachment(pdb_component_doc)
+                        for prop_item, prop_id in self.ldb_component_prop_info["QC_properties"].items():
                             logger.info("Property Item: " + str(prop_item))
                             if prop_id != "":
                                 prop_doc = super().getPrFromLocalDB(prop_id)
-                                self.__upload_prop_functions(module_doc, prop_doc)
+                                self.__upload_prop_functions(pdb_component_doc, prop_doc)
 
                     if stage == "MODULERECEPTION":
                         next_stage = "complete"
-                        localdb.QC.module.status.update_one( {"_id": ObjectId(str(module_QC_info["_id"]))}, {"$set": {"latestSyncedStage": next_stage}} )
+                        localdb.QC.module.status.update_one( {"_id": ObjectId(str(self.ldb_component_QC_info["_id"]))}, {"$set": {"latestSyncedStage": next_stage}} )
                     else:
-                        next_stage = QC_info["stage_flow"][QC_info["stage_flow"].index(stage)+1]
-                        #pd_client.post("setComponentStage", json = {"component":msn, "stage":next_stage})
-                        localdb.QC.module.status.update_one( {"_id": ObjectId(str(module_QC_info["_id"]))}, {"$set": {"latestSyncedStage": next_stage}} )
-                    upload_status[stage] = "0"
-                    localdb.QC.module.status.update_one( {"_id": ObjectId(str(module_QC_info["_id"]))}, {"$set": {"upload_status": upload_status }} )
+                        next_stage = self.ldb_component_QC_info["stage_flow"][self.ldb_component_QC_info["stage_flow"].index(stage)+1]
+                        #pd_client.post("setComponentStage", json = {"component":componentSerialNumber, "stage":next_stage})
+                        localdb.QC.module.status.update_one( {"_id": ObjectId(str(self.ldb_component_QC_info["_id"]))}, {"$set": {"latestSyncedStage": next_stage}} )
+                    self.ldb_upload_status[stage] = "0"
+                    localdb.QC.module.status.update_one( {"_id": ObjectId(str(self.ldb_component_QC_info["_id"]))}, {"$set": {"upload_status": self.ldb_upload_status }} )
 
                 logger.info("")
             except Exception as e:
@@ -1535,22 +1767,23 @@ class QCResultUploader(PDInterface.PDInterface):
                     logger.info("Failed to upload result of " + str(test_item) + "...")
                     if not os.path.exists(IF_DIR):
                         os.makedirs(IF_DIR)
-                    with open(IF_DIR + '/doing_upload_' + msn + "_fail" + '.txt', 'w') as f:
+                    with open(IF_DIR + '/doing_upload_' + componentSerialNumber + "_fail" + '.txt', 'w') as f:
                         f.write(str(test_item) + '\n' + result_id)
 
         logger.info("Finished for all results!!\n")
 
-        if not os.path.exists(IF_DIR + '/doing_upload_' + msn + "_fail" + '.txt'):
-            stage_doc = self.__setStage(module_doc, module_QC_info)
+        if not os.path.exists(IF_DIR + '/doing_upload_' + componentSerialNumber + "_fail" + '.txt'):
+            stage_doc = self.__setStage(pdb_component_doc, self.ldb_component_QC_info)
             logger.info( "Chenged Stage in ITk production DB to " + stage_doc["currentStage"] + "."  )
         else:
             logger.info("Not changed Stage in ITk production DB.")
 
-        os.remove(do_filepath)
+        os.remove(doFilePath)
         try:
             shutil.rmtree("{}/attachments".format("."))
         except:
             pass
 
-        if os.path.exists(IF_DIR + '/doing_upload_' + msn + '.txt'):
-            os.remove(IF_DIR + '/doing_upload_' + msn + '.txt')
+        if os.path.exists(IF_DIR + '/doing_upload_' + componentSerialNumber + '.txt'):
+            os.remove(IF_DIR + '/doing_upload_' + componentSerialNumber + '.txt')
+        '''
diff --git a/viewer/templates/SLDOVIresult.html b/viewer/templates/displayResults/SLDOVIresult.html
similarity index 100%
rename from viewer/templates/SLDOVIresult.html
rename to viewer/templates/displayResults/SLDOVIresult.html
diff --git a/viewer/templates/adc_calibration.html b/viewer/templates/displayResults/adc_calibration.html
similarity index 100%
rename from viewer/templates/adc_calibration.html
rename to viewer/templates/displayResults/adc_calibration.html
diff --git a/viewer/templates/coplanarity.html b/viewer/templates/displayResults/coplanarity.html
similarity index 100%
rename from viewer/templates/coplanarity.html
rename to viewer/templates/displayResults/coplanarity.html
diff --git a/viewer/templates/electrical.html b/viewer/templates/displayResults/electrical.html
similarity index 100%
rename from viewer/templates/electrical.html
rename to viewer/templates/displayResults/electrical.html
diff --git a/viewer/templates/glueattachresult.html b/viewer/templates/displayResults/glueattachresult.html
similarity index 100%
rename from viewer/templates/glueattachresult.html
rename to viewer/templates/displayResults/glueattachresult.html
diff --git a/viewer/templates/irefresult.html b/viewer/templates/displayResults/irefresult.html
similarity index 100%
rename from viewer/templates/irefresult.html
rename to viewer/templates/displayResults/irefresult.html
diff --git a/viewer/templates/massresult.html b/viewer/templates/displayResults/massresult.html
similarity index 100%
rename from viewer/templates/massresult.html
rename to viewer/templates/displayResults/massresult.html
diff --git a/viewer/templates/metresult.html b/viewer/templates/displayResults/metresult.html
similarity index 100%
rename from viewer/templates/metresult.html
rename to viewer/templates/displayResults/metresult.html
diff --git a/viewer/templates/paryleneresult.html b/viewer/templates/displayResults/paryleneresult.html
similarity index 100%
rename from viewer/templates/paryleneresult.html
rename to viewer/templates/displayResults/paryleneresult.html
diff --git a/viewer/templates/pulltest.html b/viewer/templates/displayResults/pulltest.html
similarity index 100%
rename from viewer/templates/pulltest.html
rename to viewer/templates/displayResults/pulltest.html
diff --git a/viewer/templates/pullupresult.html b/viewer/templates/displayResults/pullupresult.html
similarity index 100%
rename from viewer/templates/pullupresult.html
rename to viewer/templates/displayResults/pullupresult.html
diff --git a/viewer/templates/qc_others.html b/viewer/templates/displayResults/qc_others.html
similarity index 100%
rename from viewer/templates/qc_others.html
rename to viewer/templates/displayResults/qc_others.html
diff --git a/viewer/templates/sensorIVresult.html b/viewer/templates/displayResults/sensorIVresult.html
similarity index 100%
rename from viewer/templates/sensorIVresult.html
rename to viewer/templates/displayResults/sensorIVresult.html
diff --git a/viewer/templates/thermalresult.html b/viewer/templates/displayResults/thermalresult.html
similarity index 100%
rename from viewer/templates/thermalresult.html
rename to viewer/templates/displayResults/thermalresult.html
diff --git a/viewer/templates/tuning.html b/viewer/templates/displayResults/tuning.html
similarity index 100%
rename from viewer/templates/tuning.html
rename to viewer/templates/displayResults/tuning.html
diff --git a/viewer/templates/viresult.html b/viewer/templates/displayResults/viresult.html
similarity index 100%
rename from viewer/templates/viresult.html
rename to viewer/templates/displayResults/viresult.html
diff --git a/viewer/templates/wirebondingresult.html b/viewer/templates/displayResults/wirebondingresult.html
similarity index 100%
rename from viewer/templates/wirebondingresult.html
rename to viewer/templates/displayResults/wirebondingresult.html
diff --git a/viewer/templates/wpenvelope_result.html b/viewer/templates/displayResults/wpenvelope_result.html
similarity index 100%
rename from viewer/templates/wpenvelope_result.html
rename to viewer/templates/displayResults/wpenvelope_result.html
diff --git a/viewer/templates/xrayresult.html b/viewer/templates/displayResults/xrayresult.html
similarity index 100%
rename from viewer/templates/xrayresult.html
rename to viewer/templates/displayResults/xrayresult.html
diff --git a/viewer/templates/displayTests/massresult.html b/viewer/templates/displayTests/massresult.html
new file mode 100644
index 00000000..52785fcd
--- /dev/null
+++ b/viewer/templates/displayTests/massresult.html
@@ -0,0 +1,118 @@
+<style>
+input[type="checkbox"].data {
+display: none;
+margin: 0px;
+padding: 0px;
+background-color: #ffffff;
+}
+input[type="checkbox"].data + label {
+margin: 0px;
+padding: 0px;
+border: none;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label {
+margin: 0px;
+padding: 0px;
+border: none;
+color: #3cb371;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label:hover {
+margin: 0px;
+padding: 0px;
+color: #3cb371;
+border: none;
+background-color: #ffffff;
+}
+label.data {
+margin: 0px;
+padding: 0px;
+text-align: center;
+cursor: pointer;
+color: #dddddd;
+background-color: #ffffff;
+border: none;
+}
+</style>
+<div class='row align-items-top justify-content-left'>
+  <div class='col'>
+    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of Mass Measurement</h4>
+  </div>
+</div>
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Scan
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <th scope='raw' class='text-left'>component id</td>
+              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>Stage</td>
+              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>test Type</td>
+              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>institute</td>
+              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>user</td>
+              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
+            </tr>
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
+
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Result
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for keys in component['qctest']['results']['results'] %}
+            {% if keys == 'property' %}
+            <tr>
+              <th scope='raw' class='text-left'> Scale_accuracy </td>
+              <td class='text-left'>{{ component['qctest']['results']['results'][keys]['Scale_accuracy'] }}</td>
+            </tr>
+            {% else %}
+            <tr>
+              <th scope='raw' class='text-left'> {{ keys }} </td>
+              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
+            </tr>
+            {% endif %}
+            {% endfor %}
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
diff --git a/viewer/templates/displayTests/viresult.html b/viewer/templates/displayTests/viresult.html
new file mode 100644
index 00000000..57d6c7fb
--- /dev/null
+++ b/viewer/templates/displayTests/viresult.html
@@ -0,0 +1,138 @@
+<style>
+input[type="checkbox"].data {
+display: none;
+margin: 0px;
+padding: 0px;
+background-color: #ffffff;
+}
+input[type="checkbox"].data + label {
+margin: 0px;
+padding: 0px;
+border: none;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label {
+margin: 0px;
+padding: 0px;
+border: none;
+color: #3cb371;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label:hover {
+margin: 0px;
+padding: 0px;
+color: #3cb371;
+border: none;
+background-color: #ffffff;
+}
+label.data {
+margin: 0px;
+padding: 0px;
+text-align: center;
+cursor: pointer;
+color: #dddddd;
+background-color: #ffffff;
+border: none;
+}
+</style>
+  {% if not component["qctest"]["results"]["img"] %}
+<p><font color=#ff0000>### No defects were identified ###</font></p>
+{% endif %}
+
+
+{% if component["qctest"]["results"]["img"] %}
+<h4><i class="fa fa-paint-brush"></i> Pictures of Visual Inspection</h4>
+  <div class="row align-items-left justify-content-flex-start">
+    <div class="col">
+      <table class="table table-sm table-bordered" style="font-size: 8pt; table-layout: fixed;">
+        <thead class="table-light">
+          <tr>
+            <th scope='col' class='text-left' style="word-wrap:break-word;" width=100 colspan=1 >Keys</th>
+            <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" width=200*{{component["qctest"]["results"]["anomalyNum"]["image"]}} colspan={{component["qctest"]["results"]["anomalyNum"]["image"]}}> Pictuite with anomaly </th>
+          </tr>
+          <th scope='col' class='text-left' style="word-wrap:break-word;" width=100 colspan=1 >anomaly</th>
+          {% for i in component["qctest"]["results"]["img"] %}
+              {% if component["qctest"]["results"]["results"]["anomaly"][i] %}
+                  <th scope='col' class='text-left' style="word-wrap:break-word;" width=200 colspan=1 >{{ component["qctest"]["results"]["results"]["anomaly"][i] }}</th>
+              {% else %}
+                  <th scope='col' class='text-left' style="word-wrap:break-word;" width=200 colspan=1 > comment only </th>
+              {% endif %}
+          {% endfor %}
+        </thead>
+        <tbody>
+          <tr>
+            <th scope='raw' class='text-left'> picture </td>
+            {% for i in component["qctest"]["results"]["img"] %}
+                <td scope="col" class="text-left" style="word-wrap:break-word;">
+                <a href={{ component["qctest"]["results"]["img"][i] }} target="_brank" rel="noopener noreferrer">
+                  <img src={{ component["qctest"]["results"]["img"][i] }} title= "Click to expand" width="300px"></img>
+                </a>
+                </td>
+            {% endfor %}
+           </tr>
+           <tr>
+             <th scope='raw' class='text-left'> comment </td>
+             {% for i in component["qctest"]["results"]["img"] %}
+                 <td scope="col" class="text-left" style="word-wrap:break-word;"> {{component["qctest"]["results"]["results"]["comment"][i]}} </td>
+             {% endfor %}
+           </tr>
+        </tbody>
+      </table>
+    </div>
+  </div>
+{% endif %}
+
+
+<p><a href="{{ component['qctest']['results']['orig_cache'] }}"><img src={{ component["qctest"]["results"]["thumb"] }} /></a></p>
+
+<p>
+  <a href="{{ component['qctest']['results']['orig_cache'] }}" download>
+    <button type="button" class="btn btn-info">Download Full Image</button>
+  </a>
+  <a href="{{ url_for('picture_data_api.picData', id=component['_id'], collection=component['collection'], runId=component['qctest']['results']['runId']) }}">
+    <button type="button" class="btn btn-info">Compare w/ Refs.</button>
+  </a>
+</p>
+
+<div class='row align-items-top justify-content-left' style="margin-top: 20px;">
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Scan
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <th scope='raw' class='text-left'>component id</td>
+              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>Stage</td>
+              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>test Type</td>
+              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>institute</td>
+              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>user</td>
+              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
+            </tr>
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
+
diff --git a/viewer/templates/displayTests/wirebondingresult.html b/viewer/templates/displayTests/wirebondingresult.html
new file mode 100644
index 00000000..e42f747c
--- /dev/null
+++ b/viewer/templates/displayTests/wirebondingresult.html
@@ -0,0 +1,148 @@
+<style>
+input[type="checkbox"].data {
+display: none;
+margin: 0px;
+padding: 0px;
+background-color: #ffffff;
+}
+input[type="checkbox"].data + label {
+margin: 0px;
+padding: 0px;
+border: none;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label {
+margin: 0px;
+padding: 0px;
+border: none;
+color: #3cb371;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label:hover {
+margin: 0px;
+padding: 0px;
+color: #3cb371;
+border: none;
+background-color: #ffffff;
+}
+label.data {
+margin: 0px;
+padding: 0px;
+text-align: center;
+cursor: pointer;
+color: #dddddd;
+background-color: #ffffff;
+border: none;
+}
+</style>
+<div class='row align-items-top justify-content-left'>
+  <div class='col'>
+    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of Wirebonding Information</h4>
+  </div>
+</div>
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Scan
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <th scope='raw' class='text-left'>component id</td>
+              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>Stage</td>
+              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>test Type</td>
+              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>institute</td>
+              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>user</td>
+              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
+            </tr>
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
+
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    <i class='fa fa-file'></i> Result
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for keys in component['qctest']['results']['results'] %}
+            {% if keys != 'property' %}
+            <tr>
+              <th scope='raw' class='text-left'> {{ keys }} </td>
+              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
+            </tr>
+            {% endif %}
+            {% endfor %}
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+      <i class='fa fa-file'></i> Property
+    </h4>
+    {% if component['qctest']['results'] %}
+    <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+      <thead class='table-light'>
+        <tr>
+          <th scope='col' class='text-left'>Key</th>
+          <th scope='col' class='text-left'>Data</th>
+        </tr>
+      </thead>
+      <tbody>
+        {% for keys in component['qctest']['results']['results']['property'] %}
+        {% if keys != 'Bond_program' %}
+        <tr>
+          <th scope='raw' class='text-left'> {{ keys }} </td>
+          <td class='text-left'>{{ component['qctest']['results']['results']['property'][keys] }}</td>
+        </tr>
+        {% else %}
+        {% if component['qctest']['results']['results']['property'][keys] != "" %}
+        <tr>
+          <th scope='raw' class='text-left'> {{ keys }} </td>
+          <td class='text-left'><a href="/localdb/static/qc_attachment/Bonding_Program.dat" download><i class="fa fa-download "></i> Download Bonding Program</a></td>
+        </tr>
+        {% else %}
+        <tr>
+          <th scope='raw' class='text-left'> {{ keys }} </td>
+          <td class='text-left'><font color=#ff0000> No Bonding Program </font></td>
+        </tr>
+        {% endif %}
+        {% endif %}
+        {% endfor %}
+      </tbody>
+    </table>
+    {% endif %}
+  </div>
+</div>
diff --git a/viewer/templates/displayTests/wpenvelope_result.html b/viewer/templates/displayTests/wpenvelope_result.html
new file mode 100644
index 00000000..0a9963d9
--- /dev/null
+++ b/viewer/templates/displayTests/wpenvelope_result.html
@@ -0,0 +1,111 @@
+<style>
+input[type="checkbox"].data {
+display: none;
+margin: 0px;
+padding: 0px;
+background-color: #ffffff;
+}
+input[type="checkbox"].data + label {
+margin: 0px;
+padding: 0px;
+border: none;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label {
+margin: 0px;
+padding: 0px;
+border: none;
+color: #3cb371;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label:hover {
+margin: 0px;
+padding: 0px;
+color: #3cb371;
+border: none;
+background-color: #ffffff;
+}
+label.data {
+margin: 0px;
+padding: 0px;
+text-align: center;
+cursor: pointer;
+color: #dddddd;
+background-color: #ffffff;
+border: none;
+}
+</style>
+<div class='row align-items-top justify-content-left'>
+  <div class='col'>
+    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of This Test</h4>
+  </div>
+</div>
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Scan
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <th scope='raw' class='text-left'>component id</td>
+              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>current Stage</td>
+              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>test Type</td>
+              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>institute</td>
+              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>user name</td>
+              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
+            </tr>
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
+
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Result
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for keys in component['qctest']['results']['results'] %}
+            <tr>
+              <th scope='raw' class='text-left'> {{ keys }} </td>
+              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
+            </tr>
+            {% endfor %}
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
diff --git a/viewer/templates/displayTests/xrayresult.html b/viewer/templates/displayTests/xrayresult.html
new file mode 100644
index 00000000..197154b1
--- /dev/null
+++ b/viewer/templates/displayTests/xrayresult.html
@@ -0,0 +1,281 @@
+<style>
+input[type="checkbox"].data {
+display: none;
+margin: 0px;
+padding: 0px;
+background-color: #ffffff;
+}
+input[type="checkbox"].data + label {
+margin: 0px;
+padding: 0px;
+border: none;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label {
+margin: 0px;
+padding: 0px;
+border: none;
+color: #3cb371;
+background-color: #ffffff;
+}
+input[type="checkbox"].data:checked + label:hover {
+margin: 0px;
+padding: 0px;
+color: #3cb371;
+border: none;
+background-color: #ffffff;
+}
+label.data {
+margin: 0px;
+padding: 0px;
+text-align: center;
+cursor: pointer;
+color: #dddddd;
+background-color: #ffffff;
+border: none;
+}
+</style>
+<div class='row align-items-top justify-content-left'>
+  <div class='col'>
+    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of This Test</h4>
+  </div>
+</div>
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Scan
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <th scope='raw' class='text-left'>component id</td>
+              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>Stage</td>
+              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>test Type</td>
+              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>institute</td>
+              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
+            </tr>
+            <tr>
+              <th scope='raw' class='text-left'>user name</td>
+              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
+            </tr>
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
+
+<div class='row align-items-top justify-content-left'>
+  <div class='col-md-6'>
+    <h4 style='font-size: 10pt;'>
+    {% if component['qctest']['results'] %}
+      <i class='fa fa-file'></i> Result
+    {% endif %}
+    </h4>
+    {% if component['qctest']['results'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for keys in component['qctest']['results']['results'] %}
+            <tr>
+              <th scope='raw' class='text-left'> {{ keys }} </td>
+              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
+            </tr>
+            {% endfor %}
+          </tbody>
+        </table>
+    {% endif %}
+    {% if component['qctest']['results']['summery'] %}
+        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
+          <thead class='table-light'>
+            <tr>
+              <th scope='col' class='text-left'>Key</th>
+              <th scope='col' class='text-left'>Data</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for keys in component['qctest']['results']['summery'] %}
+            <tr>
+              <th scope='raw' class='text-left'> {{ keys }} </td>
+              <td class='text-left'>{{ component['qctest']['results']['summery'][keys] }}</td>
+            </tr>
+            {% endfor %}
+          </tbody>
+        </table>
+    {% endif %}
+  </div>
+</div>
+
+{% for scan in component['qctest']["results"]["plots"] %}
+<!--<h2 style="font-size: 20pt;"><i class="fa fa-caret-right"></i> {{ scan }}
+  {% if not component['qctest']["results"]["plots"][scan]["rootsw"] %}
+  <font color=#ff0000>### NO PLOTTING SOFTWARE ###</font>
+  {% endif %}
+</h2>
+
+<div class="row align-items-center justify-content-flex-start">
+  <div class="col">
+    {% for result in component['qctest']["results"]["plots"][scan]["results"] %}
+    <h4 style="font-size: 10pt;">
+      <i class="fa fa-caret-right"></i> {{ result["mapType"] }}
+      <a href="/localdb/plotData?testRunId={{ result['runId'] }}&mapType={{ result['mapType'] }}">plotly</a>
+    </h4>
+    <table class="table table-sm table-bordered" style="font-size: 8pt; table-layout: fixed;">
+      <thead class="table-light">
+        <tr>
+          {% for chip, data in result["chips"].items() %}
+          {% if not data["num"]==0 %}
+          <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" width={{ data["length"] }} colspan={{
+            data["num"] }}>{{ chip }}</th>
+          {% endif %}
+          {% endfor %}
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          {% for chip, data in result["chips"].items() %}
+          {% for plot in data["plots"] %}
+          {{ chip }}
+          <td scope="col" class="text-left" style="word-wrap:break-word;">
+            <a href={{ plot["url"] }} target="_brank" rel="noopener noreferrer">
+              <img src={{ plot["url"] }} title={{ plot["name"] }} width={{ data["width"] }} height={{ data["width"]
+                }}></img>
+            </a>
+          </td>
+          {% endfor %}
+          {% endfor %}
+        </tr>
+      </tbody>
+    </table>
+    {% endfor %}
+  </div>
+</div>
+-->
+
+
+<style>
+  img.plot-img:hover {
+    border: 0.5px solid #CCC;
+    transform: scale(2.5);
+  }
+</style>
+<script>
+  document.addEventListener("DOMContentLoaded", function () {
+    var lazyImages = [].slice.call(document.querySelectorAll("img.plot-img"));
+
+    if ("IntersectionObserver" in window) {
+      let lazyImageObserver = new IntersectionObserver(function (entries, observer) {
+        entries.forEach(function (entry) {
+          if (entry.isIntersecting) {
+            let lazyImage = entry.target;
+            lazyImage.src = lazyImage.dataset.src;
+            if (typeof lazyImage.dataset.srcset === "undefined") {
+            } else {
+              lazyImage.srcset = lazyImage.dataset.srcset;
+            }
+            lazyImage.classList.remove("plot-img");
+            lazyImageObserver.unobserve(lazyImage);
+          }
+        });
+      });
+
+      lazyImages.forEach(function (lazyImage) {
+        lazyImageObserver.observe(lazyImage);
+      });
+    } else {
+      // Possibly fall back to a more compatible method here
+    }
+  });
+</script>
+<h3><i class='fa fa-cog'></i> Result Plots for {{ scan }}</h3>
+
+    {% for result in component['qctest']["results"]["plots"][scan]["results"]|sort(attribute='mapType')|reverse %}
+    <h4>
+      <i class="fa fa-caret-right"></i> <b>{{ result["mapType"] }}</b>
+      <a href="/localdb/plotData?testRunId={{ result['runId'] }}&mapType={{ result['mapType'] }}"
+        style="font-size: 50%;">[plotly]</a>
+    </h4>
+    <div style="display: flex; flex-wrap: wrap;">
+      {% for chip, data in result["chips"].items() %}
+      {% if not data["num"]==0 %}
+      <div width={{ data["length"] }} align="left">
+        <table class="table table-sm table-bordered" style="font-size: 8pt;">
+          <thead class="table-light">
+            <tr>
+              <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" colspan={{ data["num"] }}>{{ chip }}
+              </th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr style="display: flex; flex-wrap: wrap; background: #DDD; max-width: 100%">
+              {% for plot in data["plots"] %}
+              <td scope="col" class="text-left" style="word-wrap:break-word;">
+                <a href={{ plot["url"] }} target="_brank" rel="noopener noreferrer">
+                  <img class="plot-img" src="static/assets/images/dummy.png" data-src={{ plot["url"] }} title={{
+                    plot["name"] }} width={{ data["width"] }} height={{ data["height"] }}></img>
+                </a>
+              </td>
+              {% endfor %}
+            </tr>
+          </tbody>
+        </table>
+      </div>
+      {% endif %}
+      {% endfor %}
+    </div>
+    {% endfor %}
+
+    <!--<h4 style="font-size: 10pt;"><i class="fa fa-paint-brush"></i> PLOT
+      {% if not component['qctest']["results"]["plots"][scan]["rootsw"] %}
+      <font color=#ff0000>### NO PLOTTING SOFTWARE ###</font>
+      {% elif component['qctest']["results"]["plots"][scan]["jsroot"] %}
+      <a href="javascript:displayRoot()">JSROOT</a>
+      {% endif %}
+    </h4>
+    {% if component['qctest']["results"]["plots"][scan]["jsroot"] %}
+    <div class="row align-items-center justify-content-flex-start">
+      <script src="static/jsroot/scripts/JSRootCore.js?gui"></script>
+      <div id="simpleGUI" path={{ component['qctest']["results"]["plots"][scan]["jsroot"]["path"] }} files={{
+        component['qctest']["results"]["plots"][scan]["jsroot"]["files"] }}
+        style="width:100%;height:600px;margin-bottom:10px;position:relative">
+        loading scripts ...
+      </div>
+      <script type="text/javascript">
+        document.getElementById("simpleGUI").style.display = "none";
+        function displayRoot() {
+          const p1 = document.getElementById("simpleGUI");
+          if (p1.style.display == "block") {
+            p1.style.display = "none";
+          } else {
+            p1.style.display = "block";
+          }
+        }
+      </script>
+    </div>
+  {% endif %}-->
+
+
+
+{% endfor %}
diff --git a/viewer/templates/plot.html b/viewer/templates/electrical_test/plot.html
similarity index 100%
rename from viewer/templates/plot.html
rename to viewer/templates/electrical_test/plot.html
diff --git a/viewer/templates/result.html b/viewer/templates/electrical_test/result.html
similarity index 100%
rename from viewer/templates/result.html
rename to viewer/templates/electrical_test/result.html
diff --git a/viewer/templates/selection.html b/viewer/templates/electrical_test/selection.html
similarity index 100%
rename from viewer/templates/selection.html
rename to viewer/templates/electrical_test/selection.html
-- 
GitLab


From 116c7c0516313ddc0a42346b8506a82b5044baab Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Sun, 24 Jul 2022 16:56:41 +0900
Subject: [PATCH 5/7] fixing typo

---
 viewer/itkpd-interface/lib/upload_results.py  |   2 +-
 viewer/pages/component.py                     |  42 ++-
 viewer/templates/comment.html                 |  17 +-
 viewer/templates/component.html               | 158 ++++------
 viewer/templates/components_table.html        |  18 --
 .../templates/displayResults/qc_others.html   |  13 +-
 viewer/templates/displayResults/tuning.html   |  13 +-
 viewer/templates/displayTests/massresult.html | 118 --------
 viewer/templates/displayTests/viresult.html   | 138 ---------
 .../displayTests/wirebondingresult.html       | 148 ---------
 .../displayTests/wpenvelope_result.html       | 111 -------
 viewer/templates/displayTests/xrayresult.html | 281 ------------------
 viewer/templates/latest_test_index.html       |  22 +-
 viewer/templates/nomodule_result.html         |   2 +-
 viewer/templates/result_tranceiver.html       |   2 +-
 .../templates/show_analysis_result.html.tmp~  |  41 ---
 viewer/templates/show_analysis_result.html~   |  41 ---
 viewer/templates/summary_index.html           |  15 +-
 viewer/templates/upload_flag.html             |   4 +-
 19 files changed, 140 insertions(+), 1046 deletions(-)
 delete mode 100644 viewer/templates/displayTests/massresult.html
 delete mode 100644 viewer/templates/displayTests/viresult.html
 delete mode 100644 viewer/templates/displayTests/wirebondingresult.html
 delete mode 100644 viewer/templates/displayTests/wpenvelope_result.html
 delete mode 100644 viewer/templates/displayTests/xrayresult.html
 delete mode 100644 viewer/templates/show_analysis_result.html.tmp~
 delete mode 100644 viewer/templates/show_analysis_result.html~

diff --git a/viewer/itkpd-interface/lib/upload_results.py b/viewer/itkpd-interface/lib/upload_results.py
index 4f1507e4..38e4ad6b 100755
--- a/viewer/itkpd-interface/lib/upload_results.py
+++ b/viewer/itkpd-interface/lib/upload_results.py
@@ -1399,7 +1399,7 @@ class QCResultUploader(PDInterface.PDInterface):
         json = self.__createElecTestTemplate(child_doc, self.testType, timestampAsString)
         json["properties"] = {"QC_STAGE":self.ldb_test_doc["currentStage"]}
         json["results"] = self.__getElecTestAnalysisResult(self.ldb_test_doc, chip_name)
-        json["runNumber"] = str( self.ldb_test_doc["_id"] ):
+        json["runNumber"] = str( self.ldb_test_doc["_id"] )
 
         return self.pd_client.post( "uploadTestRunResults", json=json)
 
diff --git a/viewer/pages/component.py b/viewer/pages/component.py
index 9464c629..7c27a009 100755
--- a/viewer/pages/component.py
+++ b/viewer/pages/component.py
@@ -36,6 +36,7 @@ def show_component():
     # component info
     this_component_doc = setComponentInfo(session.get("this", None), session["collection"])
     this_component_doc["name_delim"] = delim_SN( this_component_doc['name'] )
+    this_component_doc["typeinfo"]   = SN_typeinfo( this_component_doc['name'] )
 
     # comment
     comments = setComments(session.get("this", None), session.get("runId",None), this_component_doc)
@@ -54,6 +55,7 @@ def show_component():
 
     # set summary
     summary = setQCSummary(session.get("this", None))
+    summary_pdb = setQCSummaryAtProdDB(session.get("this", None))
     
     latest_qc_status = localdb.QC.module.status.find_one( {"component":session.get("this", None),"proddbVersion":proddbv} )
 
@@ -150,6 +152,7 @@ def show_component():
       "electrical": electrical,
       "qctest":qctest,
       "summary": summary,
+      "summary_pdb": summary_pdb,
       "upload_status": upload_status,
       "flow_version": flow_version,
       "latest_tests": latest_tests,
@@ -397,9 +400,10 @@ def analyze_scan():
             for _id in this_run_ids:
                 if _id != "":
                     run_ids_without_blank.append(_id)
+            
             table_docs["run"] = ea.createPartSummary( this_run_ids, table_docs["scans"]["scantypes"])
             for this_run_id in this_run_ids:
-                table_docs["plots"].append(setPlots(table_docs["_id"], "collection", this_run_id, True, False))
+                table_docs["plots"].append(setPlots(table_docs["_id"], "collection", this_run_id, True, True))
 
             commit_doc = ea.createElecTestDocs( run_ids_without_blank, table_docs["scans"] )
             if table_docs["scans"]["analysis"]["run"]:
@@ -455,7 +459,7 @@ def analyze_scan():
     table_docs["total"] = len(table_docs["run"])
 
 
-    return render_template( "selection.html", table_docs=table_docs, timezones=pytz.all_timezones )
+    return render_template( "electrical_test/selection.html", table_docs=table_docs, timezones=pytz.all_timezones )
 
 @component_api.route("/upload_flag", methods=["GET", "POST"])
 def upload_flag():
@@ -484,7 +488,7 @@ def upload_flag():
                 result_para["flag"] = table_docs["flag"]
             elif "TUNING" in table_docs["test"]:
                 result_para["flag"] = table_docs["flag"]
-                temp = table_docs["test"].split("_")[1].replace("min", "-")
+                temp = table_docs["test"].split("_")[1].replace("MINUS", "-").replace("DEG","")
                 result_para["setting_temp"] = int(temp)
 
             new_flag_doc = {
@@ -661,18 +665,18 @@ def select_test():
 
         elif table_docs["pstage"] == "nextcomplete":
             if not table_docs["nstage"]:
-                table_docs["text"] = "Please select stage from pull-down menue..."
+                table_docs["text"] = "Please select stage from pull-down menu..."
                 table_docs["pstage"] = "complete"
                 qc_status = localdb.QC.module.status.find_one({"component" : str(this_cp["_id"])})
                 stage_list = [item for item in qc_status["QC_results"]]
                 table_docs["stage"] = stage_list[stage_list.index(table_docs["stage"])-1]
                 table_docs["selectstage"] = skipNextStage(this_cp["_id"], table_docs["stage"])
-                return render_template("selection.html", table_docs=table_docs, timezones=pytz.all_timezones)
+                return render_template("electrical_test/selection.html", table_docs=table_docs, timezones=pytz.all_timezones)
             localdb.QC.module.status.update({"component":str(this_cp["_id"]),"proddbVersion":proddbv},{"$set":{"currentStage": table_docs["nstage"]}})
             #table_docs["stage"] = table_docs["nstage"]
 
     table_docs["total"] = len(table_docs["run"])
-    return render_template( "selection.html", table_docs=table_docs, timezones=pytz.all_timezones )
+    return render_template( "electrical_test/selection.html", table_docs=table_docs, timezones=pytz.all_timezones )
 
 
 @component_api.route("/set_stage", methods=["GET", "POST"])
@@ -879,6 +883,7 @@ def setComponentInfo(i_oid, i_col):
     session["unit"] = this["componentType"].lower()  ### TODO wakarinikui
     docs = {
         "name": this["name"],
+        "component":i_oid,
         "stage": qc_doc.get("currentStage","..."),
         "parents": parents,
         "children": children,
@@ -925,6 +930,24 @@ def setQCSummary(i_oid):
         summary[stage] = doc["QC_results"][stage]
     return summary
 
+def setQCSummaryAtProdDB(i_oid):
+    summary = {}
+    doc = localdb.QC.module.status.find_one( {"component":i_oid,"proddbVersion":proddbv} )
+    
+    
+    if doc == None:
+        return summary
+
+    qcDoc = userdb.QC.status.find_one( {"code":doc['componentType'] } )
+    stage_flow = qcDoc['stage_flow']
+
+    cstage = doc["currentStage"]
+    for stage in stage_flow:
+        if stage == cstage:
+            break
+        summary[stage] = doc["QC_results_pdb"][stage]
+    return summary
+
 def setLatestQCSummary(i_oid):
 
     tests = {}
@@ -1492,12 +1515,17 @@ def setCount():  # TODO ./dev/component.py
 # Set Result Plots by ROOT CXX
 def setPlots(i_oid, i_col, i_tr_oid, selection = False, dumpPlots = True):  # TODO ./dev/component.py
     plots = {}
+
+    logger.info( 'setPlots(): {}, {}, {}, {}, {}'.format( i_oid, i_col, i_tr_oid, selection, dumpPlots ) )
+    
     if not i_tr_oid:
         return plots
 
     if localdb.testRun.find_one({"_id": ObjectId(i_tr_oid)}) == None:
         return plots
 
+    logger.info( 'setPlots(): found {} in localdb.testRun'.format( i_tr_oid ) )
+    
     plot_root.retrieveFiles(localdb, i_tr_oid, selection)
 
     if dumpPlots:
@@ -2040,7 +2068,7 @@ class ElectricalAnalyzer:
     def createPartSummary( self, run_ids, scantype ):
         list_ = []
         for index,tr_oid in enumerate(run_ids):
-           if tr_oid:
+           if tr_oid != "":
                 query = {"_id": ObjectId(tr_oid)}
                 this_run = localdb.testRun.find_one(query)
                 testType = this_run["testType"]
diff --git a/viewer/templates/comment.html b/viewer/templates/comment.html
index bb833a44..fa9edae7 100644
--- a/viewer/templates/comment.html
+++ b/viewer/templates/comment.html
@@ -6,8 +6,9 @@
            <tr>
              <th scope="col" width="50%" class="text-left">Comment</th>
              <th scope="col" width="15%" class="text-left">Name</th>
-             <th scope="col" width="15%" class="text-left">Institution</th>
+             <!--th scope="col" width="15%" class="text-left">Institution</th-->
              <th scope="col" width="10%" class="text-left">Date</th>
+             <th scope="col" class="text-left"></th>
            </tr>
        </thead>
      {% endif %}
@@ -19,24 +20,28 @@
              <th scope="col" class="text-left"><h4 style="font-size: 8pt;">{{ comment['comment'] | safe }}</h4></th>
              <!--th scope="col" class="text-left"><h4 style="font-size: 8pt;"></h4>{{ comment['componentType'] }}</th-->
              <th scope="col" class="text-left"><h4 style="font-size: 8pt;">{{ comment['name'] }}</h4></th>
-             <th scope="col" class="text-left"><h4 style="font-size: 8pt;">{{ comment['institution'] }}</h4></th>
+             <!--th scope="col" class="text-left"><h4 style="font-size: 8pt;">{{ comment['institution'] }}</h4></th-->
              <th scope="col" class="text-left"><h4 style="font-size: 8pt;">{{ comment['datetime'] }}</h4></th>
+             <th scope="col" class="text-left"></th>
            </tr>
          {% endfor %}
        {% endif %}
 
        {% if session['logged_in'] %}
+	 <tr></tr>
          <tr>
            <form action="{{ url_for('component_api.edit_comment', id=component['_id'], collection=component['collection'], runId=session['runId']) }}" method="post" enctype="multipart/form-data">
-             <td scope="col" align="center" colspan="1"><textarea required="required" class="form-control input-normal" placeholder="comment" name = "text"></textarea></td>
+             <td scope="col" align="center" colspan="1"><textarea required="required" class="form-control input-normal" placeholder="Fill your comment here..." name = "text"></textarea></td>
              <td scope="col" align="center" colspan="1"><input type="text" required="required" class="form-control input-normal" value = "{{ session['fullname'] }}" placeholder="name" name = "text2"></td>
-             <td scope="col" align="center" colspan="1"><input type="text" required="required" class="form-control input-normal" value = "{{ session['institution'] }}" placeholder="institution" name = "text3"></td>
+             <!--td scope="col" align="center" colspan="1"><input type="text" required="required" class="form-control input-normal" value = "{{ session['institution'] }}" placeholder="institution" name = "text3"></td-->
+	     <td />
              <td scope="col" align="center middle" >
-         	    <input type="hidden" value="{{ session['user_name'] }}" name="user">
                {{ session['user_name'] }}
+               <input type="hidden" value="{{ session['user_name'] }}" name="user">
                <input type="hidden" name="id" value={{ component['_id'] }} >
                <input type="hidden" name="type" value={{ component['type'] }} >
-               <p><input type = "submit" value = "submit" style="font-size: 10pt;"></p>
+	       <button type="button" class="btn btn-primary btn-sm" type="submit" value="submit">Save</button>
+	       <!--p><input type = "submit" value = "submit" style="font-size: 10pt;"></p-->
              </td>
            </form>
          </tr>
diff --git a/viewer/templates/component.html b/viewer/templates/component.html
index f008a5ad..11d70b1e 100644
--- a/viewer/templates/component.html
+++ b/viewer/templates/component.html
@@ -71,70 +71,7 @@ th { background-color: #eeeeff; }
 		{% set name = component['info']['name'] %}
                 <h1 style="margin-top: 20px;">{{ component['info']['name_delim'] }}</br />
 		  <span style='font-size: 50%;'>
-		  {% if 'PI' == name[3:5] %}
-		  {% set isModule = True %}
-		  L0/L1 Inner Module
-		  
-		  {% elif 'PB' == name[3:5] %}
-		  {% set isModule = True %}
-		  Outer Barrel Module
-		  
-		  {% elif 'PE' == name[3:5] %}
-		  {% set isModule = True %}
-		  Outer Endcap Module
-		  
-		  {% elif 'PGM2' in name[3:7] %}
-		  {% set isModule = True %}
-		  Outer Quad Module
-		  
-		  {% elif 'PGR2' in name[3:7] %}
-		  {% set isModule = True %}
-		  Dual Chip Module
-		  
-		  {% elif 'PGR0' in name[3:7] %}
-		  {% set isModule = True %}
-		  Single Chip Module
-		  
-		  {% elif 'B' in name[5] %}
-		  {% set isModule = False %}
-		  Bare Module
-		  
-		  {% elif 'P' in name[5] %}
-		  {% set isModule = False %}
-		  PCB
-		  
-		  {% elif 'XM' in name[5:7] %}
-		  {% set isModule = True %}
-		  Tutorial Module
-		  
-		  {% elif 'XP' in name[5:7] %}
-		  {% set isModule = False %}
-		  Tutorial PCB
-		  
-		  {% elif 'XB' in name[5:7] %}
-		  {% set isModule = False %}
-		  Tutorial Bare Module
-		  
-		  {% else %}
-		  {% set isModule = False %}
-		  Others
-		  {% endif %}
-		  
-		  
-		  {% if isModule == True %}
-		  
-		   / 
-		  {% if '0' == name[7] %}
-		  RD53A
-		  {% elif '1' == name[7] %}
-		  ITkPix_v1.0
-		  {% elif '2' == name[7] %}
-		  ITkPix_v1.1
-		  {% elif '3' == name[7] %}
-		  ITkPix_v2
-		  {% endif %}
-		  {% endif %}
-		  
+		    {{ component['info']['typeinfo'] }}
 		</span><br />
 		  <a href='https://uuappg01-eu-w-1.plus4u.net/ucl-itkpd-maing01/dcb3f6d1f130482581ba1e7bbe34413c/componentView?code={{component["info"]["proID"]}}' target="_blank"
                      rel="noopener noreferrer" style="font-size: 30%;"><i class="fa fa-external-link "></i>&nbsp;&nbsp;[ITkPD: {{component['info']['proID']}}]</a></h1>
@@ -159,7 +96,7 @@ th { background-color: #eeeeff; }
                       </h2>
                     {% endif %}
 
-		      <h3><span style="font-size: 70%;">Current QC Stage:</span> {{ component['info']['stage'] }}</h3>
+		      <!--h3><span style="font-size: 70%;">Current QC Stage:</span> {{ component['info']['stage'] }}</h3-->
                     {% if session['logged_in'] and ( component['info']['type'] == "module" or component['info']['type'] == "bare_module" or component['info']['type'] == "module_pcb" ) %}
                       <a href="{{ url_for('component_api.customize_module', module=component["info"]["name"])}}"><button type="button" class="btn btn-primary" style="margin-left:10px;"><i class="fa fa-gear "></i> Customize Module Stage</button></a>
                       <a href="{{ url_for('component_api.result_transceiver', module=component["info"]["name"], stage='select')}}"><button type="button" class="btn btn-primary" style="margin-left:10px;"><i class="fa fa-paper-plane-o "></i> Upload/Download QC-test results</button></a>
@@ -181,21 +118,29 @@ th { background-color: #eeeeff; }
                     <table class="table table-sm table-bordered" style="font-size: 8pt;">
                       <thead class="table-light">
                         <tr>
-                          <th scope="col" class="text-left" width="100">Item</th>
+                          <th scope="col" class="text-left" width="200">Item</th>
                           <th scope="col" class="text-left">Value</th>
                         </tr>
                       </thead>
                       <tbody>
                         <tr>
-                          <th scope="raw" class="text-left" width="100">
+                          <th scope="raw" class="text-left" width="200">
                             Serial Number
                           </th>
                           <td>
-                            {{ component['info']['name_delim'] }}
+                            {{ component['info']['name'] }}
+                          </td>
+                        </tr>
+                        <tr>
+                          <th scope="raw" class="text-left" width="200">
+                            LocalDB Component ID
+                          </th>
+                          <td>
+                            {{ component['info']['component'] }}
                           </td>
                         </tr>
                         <tr>
-                          <th scope="raw" class="text-left" width="100">
+                          <th scope="raw" class="text-left" width="200">
                             Component Type
                           </th>
                           <td>
@@ -204,7 +149,7 @@ th { background-color: #eeeeff; }
                         </tr>
 			{% if isModule == True %}
                         <tr>
-                          <th scope="raw" class="text-left" width="100">
+                          <th scope="raw" class="text-left" width="200">
                             FE type
                           </th>
                           <td>
@@ -214,7 +159,7 @@ th { background-color: #eeeeff; }
 			{% endif %}
                         {% if component['info']['parents'] %}
                         <tr>
-                          <th scope="raw" class="text-left" width="100">
+                          <th scope="raw" class="text-left" width="200">
                             Parent Component
                           </th>
                           <td>
@@ -228,7 +173,7 @@ th { background-color: #eeeeff; }
                         {% endif %}
                         {% if component['info']['children'] %}
                         <tr>
-                          <th scope="raw" class="text-left" width="100">Sub-Components</th>
+                          <th scope="raw" class="text-left" width="200">Sub-Components</th>
                           <td>
 			    
                             {% for child in component['info']['children'] %}
@@ -264,22 +209,24 @@ th { background-color: #eeeeff; }
         </div>
 
 
-
+	<!-- Test Result Section -->
+	
+	<!-- For Electrical Scan Result -->
         {% if component['electrical']['results'] %}
 	<hr />
-        <h3>Scan Result: {{ component['electrical']['results']['info']['testType'] }} / run {{ component['electrical']['results']['info']['runNumber'] }}
+        <h3>Scan Result: {{ component['electrical']['results']['info']['testType'] }} / run {{ component['electrical']['results']['info']['runNumber'] }} (Stage: {{ component['electrical']['results']['info']['stage'] }}) 
 	  <br /><span style="font-size: 50%;">(ObjectId: {{ component['_id'] }})</span></h3>
         {% endif %}
         {% if component['electrical']['plots'] %}
-          <br>
-          {% include "plot.html" %}
+        <br>
+        {% include "electrical_test/plot.html" %}
         {% endif %}
-
+	
         {% if component['electrical']['results'] %}
-          <br>
-          {% include "result.html" %}
+        <br>
+        {% include "electrical_test/result.html" %}
         {% endif %}
-
+	
         {% if component['electrical']['dcs'] %}
         <h4 style="font-size: 10pt;"><i class="fa fa-paint-brush"></i> DCS
           {% if not component['electrical']['dcs']['dcs_data_exist'] %}
@@ -289,36 +236,41 @@ th { background-color: #eeeeff; }
           {% endif %}
         </h4>
         {% endif %}
-
+	
+	
+	<!-- For Component Properties -->
         {% if component['property']['properties'] %}
-            <br>
-            <h3><i class="fa fa-angle-double-right"></i> <b><span style="color: #AAA;">Test:</span> {{ component['property']['properties']['testType'] }}</b> / {{ component['property']['properties']['currentStage'] }} </h3>
-            {% if component['property']['properties']['results'] %}
-              <br>
-              {% if component['property']['properties']['testType'] in component['property']['prop_item']['test'] %}
-                {% include component['property']['prop_item']['html'][component['property']['properties']['testType']] %}
-              {% endif %}
-            {% else %}
-              <br>
-              <h4 style='font-size: 13pt;'>This result page is being constructed.</h4>
+	  {% set properties = component['property']['properties'] %}
+          <br>
+          <h3><i class="fa fa-angle-double-right"></i> <b><span style="color: #AAA;">Test:</span> {{ properties['testType'] }}</b> (Stage: {{ properties['currentStage'] }}) </h3>
+          {% if properties['results'] %}
+          <br>
+            {% if properties['testType'] in component['property']['prop_item']['test'] %}
+              {% include component['property']['prop_item']['html'][properties['testType']] %}
             {% endif %}
+          {% else %}
+          <br>
+          <h4 style='font-size: 13pt;'>This result page is being constructed.</h4>
           {% endif %}
-	  
-          {% if component['qctest']['results'] %}
+        {% endif %}
+	
+	<!-- For Component Results -->
+        {% if component['qctest']['results'] %}
+	  {% set results = component['qctest']['results'] %}
+          <br>
+          <h3><i class="fa fa-angle-double-right"></i> <b><span style="color: #AAA;">Test:</span> {{ results['testType'] }}</b> (Stage: {{ results['currentStage'] }})</h3>
+          {% if results['results'] %}
             <br>
-            <h3><i class="fa fa-angle-double-right"></i> <b><span style="color: #AAA;">Test:</span> {{ component['qctest']['results']['testType'] }}</b> / {{ component['qctest']['results']['currentStage'] }} </h3>
-            {% if component['qctest']['results']['results'] %}
-              <br>
-              {% if component['qctest']['results']['testType'] in component['qctest']['test_item']['test'] %}
-                {% include component['qctest']['test_item']['html'][component['qctest']['results']['testType']] %}
-              {% else %}
-                {% include "qc_others.html" %}
-              {% endif %}
+            {% if results['testType'] in component['qctest']['test_item']['test'] %}
+              {% include component['qctest']['test_item']['html'][results['testType']] %}
             {% else %}
-              <br>
-              <h4 style='font-size: 13pt;'>This result page is being constructed.</h4>
+              {% include "displayResults/qc_others.html" %}
             {% endif %}
+          {% else %}
+            <br>
+            <h4 style='font-size: 13pt;'>This result page is being constructed.</h4>
           {% endif %}
+        {% endif %}
 
 
 	      {% if component['latest_tests'] %}
diff --git a/viewer/templates/components_table.html b/viewer/templates/components_table.html
index 8ba32126..b3275b71 100644
--- a/viewer/templates/components_table.html
+++ b/viewer/templates/components_table.html
@@ -1,50 +1,32 @@
 <style type="text/css">
   .balloonoya {
     position: relative;
-    /* 指定した分だけ相対的に移動 */
   }
 
   .balloonoya:hover .balloon {
     display: inline;
-    /* インライン要素として表示 */
   }
 
   .balloon {
     position: absolute;
-    /* 親要素を基準 */
     display: none;
-    /* 要素を非表示 */
     padding: 2px;
-    /* テキストの前後の余白 */
     background-color: rgba(26, 148, 255, 0.312);
-    /* 背景色(透明度) */
     width: 180px;
-    /* 吹き出し全体の幅 */
     left: 0%;
-    /* 表示位置 */
     bottom: 100%;
-    /* 表示位置 */
     margin-bottom: 12px;
-    /* 表示位置 */
     font-size: 80%;
-    /* 文字サイズ */
   }
 
   .balloon:after {
     border-top: 12px solid rgba(26, 148, 255, 0.312);
-    /* 吹き出し口の高さ・色 */
     border-left: 10px solid transparent;
-    /* 吹き出し口の幅1/2 */
     border-right: 10px solid transparent;
-    /* 吹き出し口の幅1/2 */
     bottom: -12px;
-    /* 吹き出し口の位置調整 */
     left: 5%;
-    /* 吹き出し口の横位置 */
     content: "";
-    /* コンテンツの挿入 */
     position: absolute;
-    /* 親要素を基準 */
   }
 </style>
 
diff --git a/viewer/templates/displayResults/qc_others.html b/viewer/templates/displayResults/qc_others.html
index 9bd2603e..f820b7f9 100644
--- a/viewer/templates/displayResults/qc_others.html
+++ b/viewer/templates/displayResults/qc_others.html
@@ -36,16 +36,11 @@ border: none;
 }
 </style>
 <h4>This page is being constructed.(only show raw data)</h4>
-<div class='row align-items-top justify-content-left'>
-  <div class='col'>
-    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of This Test</h4>
-  </div>
-</div>
 <div class='row align-items-top justify-content-left'>
   <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
+    <h4>
     {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
+      <i class='fa fa-file'></i> Header Info
     {% endif %}
     </h4>
     {% if component['qctest']['results'] %}
@@ -85,9 +80,9 @@ border: none;
 
 <div class='row align-items-top justify-content-left'>
   <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
+    <h4>
     {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Result
+      <i class='fa fa-file'></i> Contents
     {% endif %}
     </h4>
     {% if component['qctest']['results'] %}
diff --git a/viewer/templates/displayResults/tuning.html b/viewer/templates/displayResults/tuning.html
index 8a4a20f3..5106efbe 100644
--- a/viewer/templates/displayResults/tuning.html
+++ b/viewer/templates/displayResults/tuning.html
@@ -35,16 +35,11 @@ background-color: #ffffff;
 border: none;
 }
 </style>
-<div class='row align-items-top justify-content-left'>
-  <div class='col'>
-    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of This Test</h4>
-  </div>
-</div>
 <div class='row align-items-top justify-content-left'>
   <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
+    <h4>
     {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
+      <i class='fa fa-file'></i> Header Info
     {% endif %}
     </h4>
     {% if component['qctest']['results'] %}
@@ -84,9 +79,9 @@ border: none;
 
 <div class='row align-items-top justify-content-left'>
   <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
+    <h4>
     {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Result
+      <i class='fa fa-file'></i> Contents
     {% endif %}
     </h4>
     {% if component['qctest']['results'] %}
diff --git a/viewer/templates/displayTests/massresult.html b/viewer/templates/displayTests/massresult.html
deleted file mode 100644
index 52785fcd..00000000
--- a/viewer/templates/displayTests/massresult.html
+++ /dev/null
@@ -1,118 +0,0 @@
-<style>
-input[type="checkbox"].data {
-display: none;
-margin: 0px;
-padding: 0px;
-background-color: #ffffff;
-}
-input[type="checkbox"].data + label {
-margin: 0px;
-padding: 0px;
-border: none;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label {
-margin: 0px;
-padding: 0px;
-border: none;
-color: #3cb371;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label:hover {
-margin: 0px;
-padding: 0px;
-color: #3cb371;
-border: none;
-background-color: #ffffff;
-}
-label.data {
-margin: 0px;
-padding: 0px;
-text-align: center;
-cursor: pointer;
-color: #dddddd;
-background-color: #ffffff;
-border: none;
-}
-</style>
-<div class='row align-items-top justify-content-left'>
-  <div class='col'>
-    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of Mass Measurement</h4>
-  </div>
-</div>
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <th scope='raw' class='text-left'>component id</td>
-              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>Stage</td>
-              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>test Type</td>
-              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>institute</td>
-              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>user</td>
-              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
-            </tr>
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
-
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Result
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            {% for keys in component['qctest']['results']['results'] %}
-            {% if keys == 'property' %}
-            <tr>
-              <th scope='raw' class='text-left'> Scale_accuracy </td>
-              <td class='text-left'>{{ component['qctest']['results']['results'][keys]['Scale_accuracy'] }}</td>
-            </tr>
-            {% else %}
-            <tr>
-              <th scope='raw' class='text-left'> {{ keys }} </td>
-              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
-            </tr>
-            {% endif %}
-            {% endfor %}
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
diff --git a/viewer/templates/displayTests/viresult.html b/viewer/templates/displayTests/viresult.html
deleted file mode 100644
index 57d6c7fb..00000000
--- a/viewer/templates/displayTests/viresult.html
+++ /dev/null
@@ -1,138 +0,0 @@
-<style>
-input[type="checkbox"].data {
-display: none;
-margin: 0px;
-padding: 0px;
-background-color: #ffffff;
-}
-input[type="checkbox"].data + label {
-margin: 0px;
-padding: 0px;
-border: none;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label {
-margin: 0px;
-padding: 0px;
-border: none;
-color: #3cb371;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label:hover {
-margin: 0px;
-padding: 0px;
-color: #3cb371;
-border: none;
-background-color: #ffffff;
-}
-label.data {
-margin: 0px;
-padding: 0px;
-text-align: center;
-cursor: pointer;
-color: #dddddd;
-background-color: #ffffff;
-border: none;
-}
-</style>
-  {% if not component["qctest"]["results"]["img"] %}
-<p><font color=#ff0000>### No defects were identified ###</font></p>
-{% endif %}
-
-
-{% if component["qctest"]["results"]["img"] %}
-<h4><i class="fa fa-paint-brush"></i> Pictures of Visual Inspection</h4>
-  <div class="row align-items-left justify-content-flex-start">
-    <div class="col">
-      <table class="table table-sm table-bordered" style="font-size: 8pt; table-layout: fixed;">
-        <thead class="table-light">
-          <tr>
-            <th scope='col' class='text-left' style="word-wrap:break-word;" width=100 colspan=1 >Keys</th>
-            <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" width=200*{{component["qctest"]["results"]["anomalyNum"]["image"]}} colspan={{component["qctest"]["results"]["anomalyNum"]["image"]}}> Pictuite with anomaly </th>
-          </tr>
-          <th scope='col' class='text-left' style="word-wrap:break-word;" width=100 colspan=1 >anomaly</th>
-          {% for i in component["qctest"]["results"]["img"] %}
-              {% if component["qctest"]["results"]["results"]["anomaly"][i] %}
-                  <th scope='col' class='text-left' style="word-wrap:break-word;" width=200 colspan=1 >{{ component["qctest"]["results"]["results"]["anomaly"][i] }}</th>
-              {% else %}
-                  <th scope='col' class='text-left' style="word-wrap:break-word;" width=200 colspan=1 > comment only </th>
-              {% endif %}
-          {% endfor %}
-        </thead>
-        <tbody>
-          <tr>
-            <th scope='raw' class='text-left'> picture </td>
-            {% for i in component["qctest"]["results"]["img"] %}
-                <td scope="col" class="text-left" style="word-wrap:break-word;">
-                <a href={{ component["qctest"]["results"]["img"][i] }} target="_brank" rel="noopener noreferrer">
-                  <img src={{ component["qctest"]["results"]["img"][i] }} title= "Click to expand" width="300px"></img>
-                </a>
-                </td>
-            {% endfor %}
-           </tr>
-           <tr>
-             <th scope='raw' class='text-left'> comment </td>
-             {% for i in component["qctest"]["results"]["img"] %}
-                 <td scope="col" class="text-left" style="word-wrap:break-word;"> {{component["qctest"]["results"]["results"]["comment"][i]}} </td>
-             {% endfor %}
-           </tr>
-        </tbody>
-      </table>
-    </div>
-  </div>
-{% endif %}
-
-
-<p><a href="{{ component['qctest']['results']['orig_cache'] }}"><img src={{ component["qctest"]["results"]["thumb"] }} /></a></p>
-
-<p>
-  <a href="{{ component['qctest']['results']['orig_cache'] }}" download>
-    <button type="button" class="btn btn-info">Download Full Image</button>
-  </a>
-  <a href="{{ url_for('picture_data_api.picData', id=component['_id'], collection=component['collection'], runId=component['qctest']['results']['runId']) }}">
-    <button type="button" class="btn btn-info">Compare w/ Refs.</button>
-  </a>
-</p>
-
-<div class='row align-items-top justify-content-left' style="margin-top: 20px;">
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <th scope='raw' class='text-left'>component id</td>
-              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>Stage</td>
-              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>test Type</td>
-              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>institute</td>
-              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>user</td>
-              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
-            </tr>
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
-
diff --git a/viewer/templates/displayTests/wirebondingresult.html b/viewer/templates/displayTests/wirebondingresult.html
deleted file mode 100644
index e42f747c..00000000
--- a/viewer/templates/displayTests/wirebondingresult.html
+++ /dev/null
@@ -1,148 +0,0 @@
-<style>
-input[type="checkbox"].data {
-display: none;
-margin: 0px;
-padding: 0px;
-background-color: #ffffff;
-}
-input[type="checkbox"].data + label {
-margin: 0px;
-padding: 0px;
-border: none;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label {
-margin: 0px;
-padding: 0px;
-border: none;
-color: #3cb371;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label:hover {
-margin: 0px;
-padding: 0px;
-color: #3cb371;
-border: none;
-background-color: #ffffff;
-}
-label.data {
-margin: 0px;
-padding: 0px;
-text-align: center;
-cursor: pointer;
-color: #dddddd;
-background-color: #ffffff;
-border: none;
-}
-</style>
-<div class='row align-items-top justify-content-left'>
-  <div class='col'>
-    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of Wirebonding Information</h4>
-  </div>
-</div>
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <th scope='raw' class='text-left'>component id</td>
-              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>Stage</td>
-              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>test Type</td>
-              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>institute</td>
-              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>user</td>
-              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
-            </tr>
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
-
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    <i class='fa fa-file'></i> Result
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            {% for keys in component['qctest']['results']['results'] %}
-            {% if keys != 'property' %}
-            <tr>
-              <th scope='raw' class='text-left'> {{ keys }} </td>
-              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
-            </tr>
-            {% endif %}
-            {% endfor %}
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-      <i class='fa fa-file'></i> Property
-    </h4>
-    {% if component['qctest']['results'] %}
-    <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-      <thead class='table-light'>
-        <tr>
-          <th scope='col' class='text-left'>Key</th>
-          <th scope='col' class='text-left'>Data</th>
-        </tr>
-      </thead>
-      <tbody>
-        {% for keys in component['qctest']['results']['results']['property'] %}
-        {% if keys != 'Bond_program' %}
-        <tr>
-          <th scope='raw' class='text-left'> {{ keys }} </td>
-          <td class='text-left'>{{ component['qctest']['results']['results']['property'][keys] }}</td>
-        </tr>
-        {% else %}
-        {% if component['qctest']['results']['results']['property'][keys] != "" %}
-        <tr>
-          <th scope='raw' class='text-left'> {{ keys }} </td>
-          <td class='text-left'><a href="/localdb/static/qc_attachment/Bonding_Program.dat" download><i class="fa fa-download "></i> Download Bonding Program</a></td>
-        </tr>
-        {% else %}
-        <tr>
-          <th scope='raw' class='text-left'> {{ keys }} </td>
-          <td class='text-left'><font color=#ff0000> No Bonding Program </font></td>
-        </tr>
-        {% endif %}
-        {% endif %}
-        {% endfor %}
-      </tbody>
-    </table>
-    {% endif %}
-  </div>
-</div>
diff --git a/viewer/templates/displayTests/wpenvelope_result.html b/viewer/templates/displayTests/wpenvelope_result.html
deleted file mode 100644
index 0a9963d9..00000000
--- a/viewer/templates/displayTests/wpenvelope_result.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<style>
-input[type="checkbox"].data {
-display: none;
-margin: 0px;
-padding: 0px;
-background-color: #ffffff;
-}
-input[type="checkbox"].data + label {
-margin: 0px;
-padding: 0px;
-border: none;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label {
-margin: 0px;
-padding: 0px;
-border: none;
-color: #3cb371;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label:hover {
-margin: 0px;
-padding: 0px;
-color: #3cb371;
-border: none;
-background-color: #ffffff;
-}
-label.data {
-margin: 0px;
-padding: 0px;
-text-align: center;
-cursor: pointer;
-color: #dddddd;
-background-color: #ffffff;
-border: none;
-}
-</style>
-<div class='row align-items-top justify-content-left'>
-  <div class='col'>
-    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of This Test</h4>
-  </div>
-</div>
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <th scope='raw' class='text-left'>component id</td>
-              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>current Stage</td>
-              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>test Type</td>
-              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>institute</td>
-              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>user name</td>
-              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
-            </tr>
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
-
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Result
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            {% for keys in component['qctest']['results']['results'] %}
-            <tr>
-              <th scope='raw' class='text-left'> {{ keys }} </td>
-              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
-            </tr>
-            {% endfor %}
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
diff --git a/viewer/templates/displayTests/xrayresult.html b/viewer/templates/displayTests/xrayresult.html
deleted file mode 100644
index 197154b1..00000000
--- a/viewer/templates/displayTests/xrayresult.html
+++ /dev/null
@@ -1,281 +0,0 @@
-<style>
-input[type="checkbox"].data {
-display: none;
-margin: 0px;
-padding: 0px;
-background-color: #ffffff;
-}
-input[type="checkbox"].data + label {
-margin: 0px;
-padding: 0px;
-border: none;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label {
-margin: 0px;
-padding: 0px;
-border: none;
-color: #3cb371;
-background-color: #ffffff;
-}
-input[type="checkbox"].data:checked + label:hover {
-margin: 0px;
-padding: 0px;
-color: #3cb371;
-border: none;
-background-color: #ffffff;
-}
-label.data {
-margin: 0px;
-padding: 0px;
-text-align: center;
-cursor: pointer;
-color: #dddddd;
-background-color: #ffffff;
-border: none;
-}
-</style>
-<div class='row align-items-top justify-content-left'>
-  <div class='col'>
-    <h4 style='font-size: 13pt;'><i class='fa fa-cog'></i> Result of This Test</h4>
-  </div>
-</div>
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Scan
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <th scope='raw' class='text-left'>component id</td>
-              <td class='text-left'>{{ component['qctest']['results']['component'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>Stage</td>
-              <td class='text-left'>{{ component['qctest']['results']['currentStage'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>test Type</td>
-              <td class='text-left'>{{ component['qctest']['results']['testType'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>institute</td>
-              <td class='text-left'>{{ component['qctest']['results']['institute'] }}</td>
-            </tr>
-            <tr>
-              <th scope='raw' class='text-left'>user name</td>
-              <td class='text-left'>{{ component['qctest']['results']['user'] }}</td>
-            </tr>
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
-
-<div class='row align-items-top justify-content-left'>
-  <div class='col-md-6'>
-    <h4 style='font-size: 10pt;'>
-    {% if component['qctest']['results'] %}
-      <i class='fa fa-file'></i> Result
-    {% endif %}
-    </h4>
-    {% if component['qctest']['results'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            {% for keys in component['qctest']['results']['results'] %}
-            <tr>
-              <th scope='raw' class='text-left'> {{ keys }} </td>
-              <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
-            </tr>
-            {% endfor %}
-          </tbody>
-        </table>
-    {% endif %}
-    {% if component['qctest']['results']['summery'] %}
-        <table class='table table-sm table-bordered' style='font-size: 8pt;'>
-          <thead class='table-light'>
-            <tr>
-              <th scope='col' class='text-left'>Key</th>
-              <th scope='col' class='text-left'>Data</th>
-            </tr>
-          </thead>
-          <tbody>
-            {% for keys in component['qctest']['results']['summery'] %}
-            <tr>
-              <th scope='raw' class='text-left'> {{ keys }} </td>
-              <td class='text-left'>{{ component['qctest']['results']['summery'][keys] }}</td>
-            </tr>
-            {% endfor %}
-          </tbody>
-        </table>
-    {% endif %}
-  </div>
-</div>
-
-{% for scan in component['qctest']["results"]["plots"] %}
-<!--<h2 style="font-size: 20pt;"><i class="fa fa-caret-right"></i> {{ scan }}
-  {% if not component['qctest']["results"]["plots"][scan]["rootsw"] %}
-  <font color=#ff0000>### NO PLOTTING SOFTWARE ###</font>
-  {% endif %}
-</h2>
-
-<div class="row align-items-center justify-content-flex-start">
-  <div class="col">
-    {% for result in component['qctest']["results"]["plots"][scan]["results"] %}
-    <h4 style="font-size: 10pt;">
-      <i class="fa fa-caret-right"></i> {{ result["mapType"] }}
-      <a href="/localdb/plotData?testRunId={{ result['runId'] }}&mapType={{ result['mapType'] }}">plotly</a>
-    </h4>
-    <table class="table table-sm table-bordered" style="font-size: 8pt; table-layout: fixed;">
-      <thead class="table-light">
-        <tr>
-          {% for chip, data in result["chips"].items() %}
-          {% if not data["num"]==0 %}
-          <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" width={{ data["length"] }} colspan={{
-            data["num"] }}>{{ chip }}</th>
-          {% endif %}
-          {% endfor %}
-        </tr>
-      </thead>
-      <tbody>
-        <tr>
-          {% for chip, data in result["chips"].items() %}
-          {% for plot in data["plots"] %}
-          {{ chip }}
-          <td scope="col" class="text-left" style="word-wrap:break-word;">
-            <a href={{ plot["url"] }} target="_brank" rel="noopener noreferrer">
-              <img src={{ plot["url"] }} title={{ plot["name"] }} width={{ data["width"] }} height={{ data["width"]
-                }}></img>
-            </a>
-          </td>
-          {% endfor %}
-          {% endfor %}
-        </tr>
-      </tbody>
-    </table>
-    {% endfor %}
-  </div>
-</div>
--->
-
-
-<style>
-  img.plot-img:hover {
-    border: 0.5px solid #CCC;
-    transform: scale(2.5);
-  }
-</style>
-<script>
-  document.addEventListener("DOMContentLoaded", function () {
-    var lazyImages = [].slice.call(document.querySelectorAll("img.plot-img"));
-
-    if ("IntersectionObserver" in window) {
-      let lazyImageObserver = new IntersectionObserver(function (entries, observer) {
-        entries.forEach(function (entry) {
-          if (entry.isIntersecting) {
-            let lazyImage = entry.target;
-            lazyImage.src = lazyImage.dataset.src;
-            if (typeof lazyImage.dataset.srcset === "undefined") {
-            } else {
-              lazyImage.srcset = lazyImage.dataset.srcset;
-            }
-            lazyImage.classList.remove("plot-img");
-            lazyImageObserver.unobserve(lazyImage);
-          }
-        });
-      });
-
-      lazyImages.forEach(function (lazyImage) {
-        lazyImageObserver.observe(lazyImage);
-      });
-    } else {
-      // Possibly fall back to a more compatible method here
-    }
-  });
-</script>
-<h3><i class='fa fa-cog'></i> Result Plots for {{ scan }}</h3>
-
-    {% for result in component['qctest']["results"]["plots"][scan]["results"]|sort(attribute='mapType')|reverse %}
-    <h4>
-      <i class="fa fa-caret-right"></i> <b>{{ result["mapType"] }}</b>
-      <a href="/localdb/plotData?testRunId={{ result['runId'] }}&mapType={{ result['mapType'] }}"
-        style="font-size: 50%;">[plotly]</a>
-    </h4>
-    <div style="display: flex; flex-wrap: wrap;">
-      {% for chip, data in result["chips"].items() %}
-      {% if not data["num"]==0 %}
-      <div width={{ data["length"] }} align="left">
-        <table class="table table-sm table-bordered" style="font-size: 8pt;">
-          <thead class="table-light">
-            <tr>
-              <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" colspan={{ data["num"] }}>{{ chip }}
-              </th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr style="display: flex; flex-wrap: wrap; background: #DDD; max-width: 100%">
-              {% for plot in data["plots"] %}
-              <td scope="col" class="text-left" style="word-wrap:break-word;">
-                <a href={{ plot["url"] }} target="_brank" rel="noopener noreferrer">
-                  <img class="plot-img" src="static/assets/images/dummy.png" data-src={{ plot["url"] }} title={{
-                    plot["name"] }} width={{ data["width"] }} height={{ data["height"] }}></img>
-                </a>
-              </td>
-              {% endfor %}
-            </tr>
-          </tbody>
-        </table>
-      </div>
-      {% endif %}
-      {% endfor %}
-    </div>
-    {% endfor %}
-
-    <!--<h4 style="font-size: 10pt;"><i class="fa fa-paint-brush"></i> PLOT
-      {% if not component['qctest']["results"]["plots"][scan]["rootsw"] %}
-      <font color=#ff0000>### NO PLOTTING SOFTWARE ###</font>
-      {% elif component['qctest']["results"]["plots"][scan]["jsroot"] %}
-      <a href="javascript:displayRoot()">JSROOT</a>
-      {% endif %}
-    </h4>
-    {% if component['qctest']["results"]["plots"][scan]["jsroot"] %}
-    <div class="row align-items-center justify-content-flex-start">
-      <script src="static/jsroot/scripts/JSRootCore.js?gui"></script>
-      <div id="simpleGUI" path={{ component['qctest']["results"]["plots"][scan]["jsroot"]["path"] }} files={{
-        component['qctest']["results"]["plots"][scan]["jsroot"]["files"] }}
-        style="width:100%;height:600px;margin-bottom:10px;position:relative">
-        loading scripts ...
-      </div>
-      <script type="text/javascript">
-        document.getElementById("simpleGUI").style.display = "none";
-        function displayRoot() {
-          const p1 = document.getElementById("simpleGUI");
-          if (p1.style.display == "block") {
-            p1.style.display = "none";
-          } else {
-            p1.style.display = "block";
-          }
-        }
-      </script>
-    </div>
-  {% endif %}-->
-
-
-
-{% endfor %}
diff --git a/viewer/templates/latest_test_index.html b/viewer/templates/latest_test_index.html
index 64514ccb..3511b01e 100644
--- a/viewer/templates/latest_test_index.html
+++ b/viewer/templates/latest_test_index.html
@@ -23,7 +23,7 @@
 <div class="row align-items-top">
   <div style="padding-left: 30px;">
   {% if component["latest_tests"]["results"] %}
-  <table class="table table-lg table-bordered" style="width:500px;">
+  <table class="table table-lg table-bordered" style="width:700;">
     <thead class="bg-warning">
       <tr>
         <th scope="col" class="text-left">Test Type</th>
@@ -34,19 +34,25 @@
       {% for test in component["latest_tests"]["results"] %}
       <tr>
           <td style="word-wrap:break-word;">{{ component['qctest']['test_items'][test['name']] }}<br /><span style="color: #ccc;">({{ test["name"] }})</span></td>
+	  
           {% if test["runId"] %}
 	    <td style="word-wrap:break-word; background-color:rgb(204, 255, 223);">
-            <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='qctest', runId=test['runId']) }}">Registered [{{ test["runId"] }}]</a>
+	      <!-- Result is registered -->
+              <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='qctest', runId=test['runId']) }}">Registered [{{ test["runId"] }}]</a>
           {% else %}
 	    <td style="word-wrap:break-word; background-color:#fcc;">
+	      <!-- Result is not registered yet -->
               <strong><font style="color: red;">No result!</font></strong>
           {% endif %}
-          {% if test["scan_selection"] and session['logged_in'] %}
-	          <a href="{{ url_for('component_api.analyze_scan', id=component['_id'], stage=component['info']['stage'], test=test['name'])}}"><button type="button" class="btn btn-primary">Select scan results</button></a>
-          {% elif "TUNING" in test["name"] and session['logged_in'] or test["name"] == "ADC_CALIBRATION" and session['logged_in'] %}
-            <a
-              href="{{ url_for('component_api.upload_flag', id=component['_id'], stage=component['info']['stage'], test=test['name'])}}"><button
-                type="button" class="btn btn-primary"> Create a result </button></a>
+	      
+	  {% if session['logged_in'] %}
+              {% if test["scan_selection"] %}
+	      &nbsp;<a href="{{ url_for('component_api.analyze_scan', id=component['_id'], stage=component['info']['stage'], test=test['name'])}}"><button type="button" class="btn btn-secondary" style="font-size: 70%;">Checkout Scans</button></a>
+              {% elif "TUNING" in test["name"] and session['logged_in'] or test["name"] == "ADC_CALIBRATION" and session['logged_in'] %}
+              &nbsp;<a href="{{ url_for('component_api.upload_flag', id=component['_id'], stage=component['info']['stage'], test=test['name'])}}"><button type="button" class="btn btn-secondary" style="font-size: 70%;"> Checkout </button></a>
+	      {% else %}
+	      &nbsp;(Upload via QCHelper)
+	      {% endif %}
           {% endif %}
           </td>
       </tr>
diff --git a/viewer/templates/nomodule_result.html b/viewer/templates/nomodule_result.html
index fa0f5a1c..2c4acad8 100644
--- a/viewer/templates/nomodule_result.html
+++ b/viewer/templates/nomodule_result.html
@@ -77,7 +77,7 @@ border: none;
       
       {% if component['electrical']['plots'] %}
       <br>
-      {% include "plot.html" %}
+      {% include "electrical_test/plot.html" %}
       {% endif %}
 
         <div class='row align-items-top justify-content-center'>
diff --git a/viewer/templates/result_tranceiver.html b/viewer/templates/result_tranceiver.html
index a17c0813..c2f7cee7 100644
--- a/viewer/templates/result_tranceiver.html
+++ b/viewer/templates/result_tranceiver.html
@@ -433,7 +433,7 @@ table.toppage td.border_inner {
 <div class="container">
   <div class="row align-items-center justify-content-center">
     <div class="col">
-      {% if doc["download_list"] != [] %}
+      {% if doc["download_list"] %}
       <h3> Download has finished!</h3>
       <h4><i class='fa fa-file'></i> List of downloaded QC-test results</h4>
       <div class="row align-items-top card-body">
diff --git a/viewer/templates/show_analysis_result.html.tmp~ b/viewer/templates/show_analysis_result.html.tmp~
deleted file mode 100644
index 0dcb869d..00000000
--- a/viewer/templates/show_analysis_result.html.tmp~
+++ /dev/null
@@ -1,41 +0,0 @@
-<br>
-<h4 style='font-size: 10pt;'>
-  <i class="fa fa-file"></i> Plot
-</h4>
-<table class="table table-sm table-bordered" style="font-size: 10pt;">
-  {% for step in chip_result['plot_info']  %}
-  <p>{{ step }}</p>
-  <thead class="table-light">
-    <tr>
-      <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" >{{ step["analysis"] }}</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      {% if step["plots"].find("map") %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ {{ step["plots"]["map"] }} }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step["plots"]["map"] }}" title="{{ step["analysis"] }}" width=300 height=300 ></img>
-	</a>
-      </td>
-      {% endif %}
-      {% if step["plots"].find("proj") %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ {{ step["plots"]["proj"] }} }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step["plots"]["proj"] }}" title="{{ step["analysis"] }}" width=300 height=300 ></img>
-	</a>
-      </td>
-      {% endif %}
-      {% if step["plots"].find("badpixels") %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ {{ step["plots"]["badpixels"] }} }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step["plots"]["badpixels"] }}" title="{{ step["analysis"] }}" width=300 height=300 ></img>
-	</a>
-      </td>
-      {% endif %}
-    </tr>
-  </tbody>
-  {% endfor %}
-</table>
-
-
diff --git a/viewer/templates/show_analysis_result.html~ b/viewer/templates/show_analysis_result.html~
deleted file mode 100644
index 1c0de6fc..00000000
--- a/viewer/templates/show_analysis_result.html~
+++ /dev/null
@@ -1,41 +0,0 @@
-<br>
-<h4 style='font-size: 10pt;'>
-  <i class="fa fa-file"></i> Plot
-</h4>
-<table class="table table-sm table-bordered" style="font-size: 10pt;">
-  {% for step in chip_result['plot_info']  %}
-  <p>{{ step }}</p>
-  <thead class="table-light">
-    <tr>
-      <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" >{{ step["analysis"] }}</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      {% if 'map' in step['img'] %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ step['img']['map'] }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step['img']['map'] }}" title="{{ step["analysis"] }}" width=250 height=250 ></img>
-	</a>
-      </td>
-      {% endif %}
-      {% if 'proj' in step['img'] %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ step['img']['proj'] }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step['img']['proj'] }}" title="{{ step["analysis"] }}" width=250 height=250 ></img>
-	</a>
-      </td>
-      {% endif %}
-      {% if 'badpixels' in step['img'] %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ step['img']['badpixels'] }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step['img']['badpixels'] }}" title="{{ step["analysis"] }}" width=250 height=250 ></img>
-	</a>
-      </td>
-      {% endif %}
-    </tr>
-  </tbody>
-  {% endfor %}
-</table>
-
-
diff --git a/viewer/templates/summary_index.html b/viewer/templates/summary_index.html
index 0108488d..d776ddac 100644
--- a/viewer/templates/summary_index.html
+++ b/viewer/templates/summary_index.html
@@ -14,7 +14,7 @@
       {% endif %}
     </h4>
     <table class="table table-bordered" style="font-size: 80%; margin-left: 3%; width: 500px;">
-      <thead><th>Test</th><th>Result</th></thead>
+      <thead><th>Test</th><th>Result</th><th>ProdDB Record</th></thead>
       <tbody>
       {% for test in component["summary"][stage] %}
       <tr>
@@ -25,11 +25,20 @@
         </td>
         {% elif component["upload_status"][stage] == '0' or component["upload_status"][stage] == '1' %}
         <td align="center" style="word-wrap:break-word; background-color:rgba(204, 255, 223, 0.75);">
-          <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='qctest', runId=component['summary'][stage][test]) }}"><i class="fa fa-external-link "></i> {{ component['summary'][stage][test] }}</a>
+          <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='qctest', runId=component['summary'][stage][test]) }}"><i class="fa fa-external-link "></i> Registered {{ component['summary'][stage][test] }}</a>
         </td>
         {% else %}
         <td align="center" style="word-wrap:break-word; background-color:rgba(255, 242, 204, 0.75);">
-          <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='qctest', runId=component['summary'][stage][test]) }}"><i class="fa fa-external-link "></i></a>
+          <a href="{{ url_for('component_api.show_component', id=component['_id'], collection=component['collection'], test='qctest', runId=component['summary'][stage][test]) }}"><i class="fa fa-external-link "></i> Registered {{ component['summary'][stage][test] }}</a>
+        </td>
+        {% endif %}
+        {% if component["summary_pdb"][stage][test] == "-1" %}
+        <td align="center" style="word-wrap:break-word; background-color:rgba(255, 204, 204, 0.75);">
+          N/A
+        </td>
+        {% else %}
+        <td align="center" style="word-wrap:break-word; background-color:rgba(204, 255, 223, 0.75);">
+          <a href="https://uuappg01-eu-w-1.plus4u.net/ucl-itkpd-maing01/dcb3f6d1f130482581ba1e7bbe34413c/testRunView?id={{ component['summary_pdb'][stage][test] }}"><i class="fa fa-external-link "></i> Registered {{ component['summary_pdb'][stage][test] }}</a>
         </td>
         {% endif %}
       </tr>
diff --git a/viewer/templates/upload_flag.html b/viewer/templates/upload_flag.html
index ba2e83b4..b64b2b50 100644
--- a/viewer/templates/upload_flag.html
+++ b/viewer/templates/upload_flag.html
@@ -57,8 +57,8 @@ table.toppage td.border_inner {
         <form class="form-holizontal" role="form" method="post"
           action="{{ url_for('component_api.upload_flag', id=table_docs['_id'], stage=table_docs['stage'], test=table_docs['test']) }}"
           accept-charset="UTF-8">
-        <h4><input type="radio" name="flag" value="True" required="required" checked> Did {{ table_docs["test"] }}</h4>
-        <h4><input type="radio" name="flag" value="False" required="required"> Did not {{ table_docs["test"] }}</h4>
+        <h4><input type="radio" name="flag" value="True" required="required" checked> Carried out {{ table_docs["test"] }}</h4>
+        <h4><input type="radio" name="flag" value="False" required="required"> Did not carry out {{ table_docs["test"] }}</h4>
 
         <button type="submit" class="btn btn-primary" name="pstage" value="complete">Create flag</button>
         </form>
-- 
GitLab


From 1183d16ba263a553f4dce2b185fc0e0cdda2be71 Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Sun, 24 Jul 2022 17:20:47 +0900
Subject: [PATCH 6/7] fixing sensorIV display

---
 ...eaed37f7eac6b96452b1f0f99b9d8644c8632a4399 | Bin 1311 -> 0 bytes
 ...4051ef85d91ebdb09361d2df3bebf2a6c8db0ce648 | Bin 81446 -> 0 bytes
 ...13d36dcdf65a57d09218794f7055a2ec28aea08d26 | Bin 1140 -> 0 bytes
 ...df59fac1100a31693bb9472500cd169ceb358af463 | Bin 1344 -> 0 bytes
 viewer/json-lists/scan_list.json              |  34 +++----
 viewer/json-lists/supported_test.json         |  94 +++++++++---------
 viewer/pages/component.py                     |   2 +-
 .../displayResults/sensorIVresult.html        |   3 +-
 8 files changed, 69 insertions(+), 64 deletions(-)
 delete mode 100644 viewer/itkpd-interface/bin/.webcache/3/2/7/6/0/32760c98b5940eeaed37f7eac6b96452b1f0f99b9d8644c8632a4399
 delete mode 100644 viewer/itkpd-interface/bin/.webcache/3/8/b/c/c/38bccf53de1cc64051ef85d91ebdb09361d2df3bebf2a6c8db0ce648
 delete mode 100644 viewer/itkpd-interface/bin/.webcache/7/d/6/7/f/7d67f527ce702613d36dcdf65a57d09218794f7055a2ec28aea08d26
 delete mode 100644 viewer/itkpd-interface/bin/.webcache/c/c/8/d/1/cc8d164ab3f348df59fac1100a31693bb9472500cd169ceb358af463

diff --git a/viewer/itkpd-interface/bin/.webcache/3/2/7/6/0/32760c98b5940eeaed37f7eac6b96452b1f0f99b9d8644c8632a4399 b/viewer/itkpd-interface/bin/.webcache/3/2/7/6/0/32760c98b5940eeaed37f7eac6b96452b1f0f99b9d8644c8632a4399
deleted file mode 100644
index 4dd75339f5063115f5cbebb0f0aecdc56e61b72a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1311
zcmb7EO^@S55Jeo9KVcamffQ%DJGS#N${~{pGh${nXyRRQGwtqj(yZO>ZFff-Rx7Qz
zaNu7+G>b;C65107E=Wim_yhA(xY2fEm=)qcj@7TK-h1^N#-?HKtM4_`m6A1ly~`Be
z{`T&l&mVa1=cj`E6VHzcM;UMe7>_bO=0iFf<%Gn3Zx3UtbnPI`9?Wvc!VyG(2|)<a
z7)3eFJFu-mH#lLQJY`*xa_%_PP5oS~*4{#bUTwV@V^DymMrrRFYM`2}y(_(<QhZ5`
zP}2MGVsY_NH-%ZP9gC%*D`-YNygGe!xk#=)ou70N1GP!ERr`E)`Dl^uG3m#bi_g+o
zlFa7k9kkvyeD+SXZZOjlB#4jz4Fen{2v0Dcgrtwi&?!B1w&3#rfHiE~D%869;$W)t
z!xrt3dlV|ID$r*87O{5USz#fSv}~2lG%dI=;1PuJJytF9u_|l{sdH7RRORWa=`6)F
zWA(myf_o>Ef3>v>GHTd5mA1_GM@&v;e#^R<d|=)#xmK!74U~>8Jq#wpKH6(*5y?M~
zsg<J54u{qJ9$o+3mcr?1<c85(-QCOItsh)>hij+1NS22{QjgoR+<F`8gznjP9`o!m
z=-TDTEx>(*AG~<A2FhLSo82ij@JnK$=i#yUi7lL$gm@^Npz#ES-r2+CW(j%&`es&9
zwuYaVMhj+wL{sU$CT)TxxIjAgckh?<S>Q4`9pGpXyPzC<LbAegSlaAVl~l<32d1QP
zj05A+x%;A4@=aIa!p*BillQww$U;as_Ht1`bMEPXq&Pj~r{9d)f%_!xe1AB=gpDGX
zRzAX<Bh2G?#K(k0z%s~l|3}tH37XAX6>mD;G3t4h78_^D>yDLMzcTCZhB3Zff(hnI
zJrQvCxwU;-RehG(>Drj8o*W%n>nZ_<O}{E^9ooJGb7WZ&xW9mk2aWs{!bhBCgFNOq
z#{(3ONHoG3#W2h=7=$4nu;YrF_4M`vpbBP%*uYOll%TAcMm^6losOg1xsnoC<J3Le
tO>JBT>py;f<*wCS`@I_t)Y<aw)rEU&uJ+Dr4oq=K59)s1ZK&S9{0pY6k@^4t

diff --git a/viewer/itkpd-interface/bin/.webcache/3/8/b/c/c/38bccf53de1cc64051ef85d91ebdb09361d2df3bebf2a6c8db0ce648 b/viewer/itkpd-interface/bin/.webcache/3/8/b/c/c/38bccf53de1cc64051ef85d91ebdb09361d2df3bebf2a6c8db0ce648
deleted file mode 100644
index 9754ff2e233f2f32b2a073d455be5ca8914014ab..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 81446
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

diff --git a/viewer/itkpd-interface/bin/.webcache/7/d/6/7/f/7d67f527ce702613d36dcdf65a57d09218794f7055a2ec28aea08d26 b/viewer/itkpd-interface/bin/.webcache/7/d/6/7/f/7d67f527ce702613d36dcdf65a57d09218794f7055a2ec28aea08d26
deleted file mode 100644
index c52cdc17ff030b7f0abf5ea29797ec5fad57427a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1140
zcmb7D%Wm676b-seeqz9E5<sM9_>d?WTDZ26qORefRJ&D&GndjN<dB_*P&EipWRpey
zA`zUzXbluzb<s_M0$ub6{5PGUB*b2Z%X`n9d(J(Vj7`(Qn_m^^u9X_zZpxOg|M`Nx
zdWhT?%moi7C>X{Zml?}}ki6t$KB9SE#c>u4wlLN<?m0-a1+xmuG=~gG9Ak{>5N8#w
z_F$_)d7LmWe`Nb2<=kn|zW$Y1EYYb1wOFGg#-Ij8O{>tipn)p3L>Fp7rTCc|(Mt5>
z?DXvEo`qSZoQlHG1$e6Si<9rZIh|cRKmKwLF`&(C-EG@PMX|5zwI9B<-CJj-R}<qn
z4)G`?*$m@J5>JveN{DlXcQ1Qz^EqGzD>n-Ft9!lMpfhjlp5%^%PPH8<v%V*+pI0zi
z!<;f_m@?nT5yoW8<pKT+?t|u5iawu3&`<V|-Si&aP_5@HT3f%GIEwT96J5|ZKM~yN
zxagZ*@Dy>|G;6daxo3};--FUFFUL(HOdh`exCF{w?cL^t8u)8wVSvaOeQj&xSB`Kx
z!J|n=(6jT|WdUjh>hh?gYzcoBMhRxZnWEBNtukQ&ZV$q&Zyz`Gr_g0TO-PmuT}FpU
zNLE`8g)L9oh6<^FW34n!acJBXY+mSA-s~$}I6f`>UEKyk)<VJ|szeQvHZVPR*D~Mb
z6!~`>aCdea1boC3_g^H{uyluBW^q!DleD6Q$0L%I5d6-(?$D1>ZGE#BIm83hDY0_?
zulEw%tc6*A7~=6&0VX_d+m`}vf3P;9T^F&^PM5}XdU9}Jt*e9_R#8`5o!Ur(Ik2n_
z-G9~b(0g5Aa=@7v#z{pIoaS+sladk`l_ex;N)mS1QL~(0odI;=Q7u;RhY=05)=aYj
za!RM;(baJ)B{091JGe`2sImILe?Pite6)`)6;QX9_ZMfb=OcP>&4INX<~w(PZ&p;T
GfB7F7?O@3O

diff --git a/viewer/itkpd-interface/bin/.webcache/c/c/8/d/1/cc8d164ab3f348df59fac1100a31693bb9472500cd169ceb358af463 b/viewer/itkpd-interface/bin/.webcache/c/c/8/d/1/cc8d164ab3f348df59fac1100a31693bb9472500cd169ceb358af463
deleted file mode 100644
index a7d747d5c2d95f7d2cf4bece51a9661322c3794d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1344
zcmYk6eKb^g7{{lyQd+g6lBh;;RNQ%=44M*QN^MP8yQJK?^J6aK&h5^<lfl{Elv-Nv
zTggc|GObKeB+60rq9#^EGUc42nmRVUAz|#;)1I^c{+{1+zMt>+InRS2BEI|na|BS~
zN=yY(i=|4L=C*~;k~AxtvZGx}vv?Y6zzo7U<MZ})r7}C!8#Z2HDt~-Y63{Oc&#g2T
zS;=?x$=xJVH&DHnrr|~5YRFC#8C5ZL*5Q2pi4&?j$u38`Zanp^TAuE5ukd1Vrn8eR
zbH#g~8w(b^&fUg=?M+R47r42fPP25XzN?BA7j<7+?YQK7W6d;ReND8Go3<t;xFwbE
zcxl(hap(88UiKAT6KyWtQ7^)>JKCnWhlORN{Zd<d?Yhr-dfsS)6F(soGSF8?B*{Oe
zaJK4#!h&=z^6c^{D?(svN%pO`^DUiOx!!$6{BnoPp|Uj%2cD;lK5VVhMo@;I;*K3k
z4_G$VCZuT|JTfLm`U0DKmh08MMvnm7Lf2o}AML55^X@aY#-)YV3=LT<4l4AA-NE9(
z8VB6*tK@jb!|_&AbN{PHLwBX0`kUt(n>$ZN+vlD>sH@sN+cKr)R9#+=Rp{6pn_Ee#
z74^3L?fWa<T-j%<uw32ZxA<~$!E~EdGaD3(3Zss-r>5GzqbCjj!Ps>EOoJxt8HO{n
zzHDE*&cqVS(&<M`JL&KYWW$ZX+|&ud5%Hm`60zo0V9kNEzE)3ing(C&8hUip^rlfd
zG=k=rwCgjp+b-zmU$40z7fH$WB8NT6%b(vq8SZu|W^P;9vGUm1mt@}O5P!e<gCPf3
zetPWs`FKX7__x;CQA<0yO^sbKp4NVQ+=a3eIWy$WL#}}ZYkDI0?5I`bj>zrKey1z1
z9B7pk*tJw>TdHp*y<my$x5$sDj~w1?wEI|6{Fn2A>@U__L(aQr==R;Wt#j{W!QF!n
zrykc|O?2?dmy})WnU>*rDn3A&H9V_-#@gMRmb7<_C)Xx?6)cUHh=g|<SN?r7T=&D<
z=grU<zrHZC47>QMx-N0;yoH@r*$2A|)EUF-fpVu9eYFEwO`q9xh8&>p5c_)T{XSUa
z@QQ5>f9lfuFknF2A5>l#+{PdMn)woj>jlKmM||s8AAS##3=HeIb_RW~v8T5pK0iDn
z)1zF#tUO5{iI8`6?AXT{y>c&4_xip*7I3s55^wf+q`x!Gt~_VsU*NiS`{lmshgrsp
z-pQsZG}^?31+5hG9XmXoM$^gxECYlpt$005g1TS|b7yco7#k@CgUjY}8Ej84F3(FK
zU<7UsDG3II8W1Jxa2Sz;nqZPZ5fTa^V9dOf1PKKLgd$K<^JG~(oB+WwK*Zw+c&pfK
zwl@RC5CtUz!IX5pG9E@TRT-khNPv+Lslh=#jN=Lvfk{+}v0_z9%$tG8VL}B+QD{g2
zB-A03iqK>Wp;Tyb0#%!7wIBgU%@?6&k`!WlKpc;dNnU{$kK@K>d$HN&|A_z$QOZy(
zrZ^@M#Y=+$3Hd3NaVU5aMNv$%I1`alA~{LoDlZm`qRcOl45*p7f>QA*CI(0rg(x7D
zjKgKnBz_E=!;&FVUi2y%Cz``!^Mzc2kRydTz(XnpJU*YpL%eaAl#5D(0KlPj3RDd$
zNHiWODN-bGXP6Tbd3u)mDKQKnleYi=@83wH0Rj1c!`32l3X21>5)}!Pl<Gl~);tH5
kxy!nQ0I)f)qAfw@+T=WF7i7Tf73}<Gy`fkQ6PmsM0C1ILtN;K2

diff --git a/viewer/json-lists/scan_list.json b/viewer/json-lists/scan_list.json
index d577ef99..87804d09 100644
--- a/viewer/json-lists/scan_list.json
+++ b/viewer/json-lists/scan_list.json
@@ -6,22 +6,22 @@
   },
   "READOUT_IN_BASIC_ELECTRICAL_TEST":{
         "setting_temp":null,
-        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan.json"],
+        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
-  "READOUT_IN_BASIC_ELECTRICAL_TEST_30_DEGREE":{
+  "READOUT_IN_BASIC_ELECTRICAL_TEST_30DEG":{
         "setting_temp":30,
-        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan.json"],
+        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
-  "READOUT_IN_BASIC_ELECTRICAL_TEST_20_DEGREE":{
+  "READOUT_IN_BASIC_ELECTRICAL_TEST_20DEG":{
         "setting_temp":20,
-        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan.json"],
+        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
-  "READOUT_IN_BASIC_ELECTRICAL_TEST_min15_DEGREE":{
+  "READOUT_IN_BASIC_ELECTRICAL_TEST_MINUS15DEG":{
         "setting_temp":-15,
-        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan.json"],
+        "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
   "PIXEL_FAILURE_TEST":{
@@ -29,17 +29,17 @@
         "scantypes":["std_digitalscan","std_analogscan","std_thresholdscan","std_totscan","std_noisescan","std_crosstalkscan"],
         "analysis": { "run":true, "name":"bad_pixel_analysis" }
   },
-  "PIXEL_FAILURE_TEST_30_DEGREE":{
+  "PIXEL_FAILURE_TEST_30DEG":{
         "setting_temp":30,
         "scantypes":["std_digitalscan", "syn_analogscan", "lindiff_analogscan", "syn_thresholdscan", "lin_thresholdscan", "diff_thresholdscan", "syn_totscan", "lin_totscan", "diff_totscan", "syn_discbumpscan", "lin_discbumpscan", "diff_discbumpscan" ],
         "analysis": { "run":true, "name":"bad_pixel_analysis" }
   },
-  "PIXEL_FAILURE_TEST_20_DEGREE":{
+  "PIXEL_FAILURE_TEST_20DEG":{
         "setting_temp":20,
         "scantypes":["std_digitalscan", "syn_analogscan", "lindiff_analogscan", "syn_thresholdscan", "lin_thresholdscan", "diff_thresholdscan", "syn_totscan", "lin_totscan", "diff_totscan", "syn_discbumpscan", "lin_discbumpscan", "diff_discbumpscan" ],
         "analysis": { "run":true, "name":"bad_pixel_analysis" }
   },
-  "PIXEL_FAILURE_TEST_min15_DEGREE":{
+  "PIXEL_FAILURE_TEST_MINUS15DEG":{
         "setting_temp":-15,
         "scantypes":["std_digitalscan", "syn_analogscan", "lindiff_analogscan", "syn_thresholdscan", "lin_thresholdscan", "diff_thresholdscan", "syn_totscan", "lin_totscan", "diff_totscan", "syn_discbumpscan", "lin_discbumpscan", "diff_discbumpscan" ],
         "analysis": { "run":true, "name":"bad_pixel_analysis" }
@@ -51,22 +51,22 @@
   },
   "BUMP_BOND_QUALITY":{
         "setting_temp":null,
-        "scantypes":["std_noisescan.json","std_discbumpscan.json"],
+        "scantypes":["std_noisescan.json","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
-  "BUMP_BOND_QUALITY_30_DEGREE":{
+  "BUMP_BOND_QUALITY_30DEG":{
         "setting_temp":30,
-        "scantypes":["std_noisescan.json","std_discbumpscan.json"],
+        "scantypes":["std_noisescan.json","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
-  "BUMP_BOND_QUALITY_20_DEGREE":{
+  "BUMP_BOND_QUALITY_20DEG":{
         "setting_temp":20,
-        "scantypes":["std_noisescan.json","std_discbumpscan.json"],
+        "scantypes":["std_noisescan.json","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   },
-  "BUMP_BOND_QUALITY_min15_DEGREE":{
+  "BUMP_BOND_QUALITY_MINUS15DEG":{
         "setting_temp":-15,
-        "scantypes":["std_noisescan.json","std_discbumpscan.json"],
+        "scantypes":["std_noisescan.json","std_discbumpscan"],
         "analysis": { "run":false, "name":"" }
   }
 }
diff --git a/viewer/json-lists/supported_test.json b/viewer/json-lists/supported_test.json
index 621ea515..c5bc13cd 100644
--- a/viewer/json-lists/supported_test.json
+++ b/viewer/json-lists/supported_test.json
@@ -23,64 +23,68 @@
     "OPTICAL",
     "PARYLENE",
     "PIXEL_FAILURE_TEST",
-    "PIXEL_FAILURE_TEST_20_DEGREE",
-    "PIXEL_FAILURE_TEST_30_DEGREE",
-    "PIXEL_FAILURE_TEST_min15_DEGREE",
+    "PIXEL_FAILURE_TEST_20DEG",
+    "PIXEL_FAILURE_TEST_30DEG",
+    "PIXEL_FAILURE_TEST_MINUS15DEG",
     "RD53A_PULL-UP_RESISTOR",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST_30_DEGREE",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST_20_DEGREE",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST_min15_DEGREE",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST_30DEG",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST_20DEG",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST_MINUS15DEG",
     "REGISTER_TEST",
     "SENSOR_IV",
-    "SENSOR_IV_20_DEGREE",
-    "SENSOR_IV_30_DEGREE",
-    "SENSOR_IV_min15_DEGREE",
+    "SENSOR_IV_20DEG",
+    "SENSOR_IV_30DEG",
+    "SENSOR_IV_MINUS15DEG",
     "SLDO_VI",
-    "XRAY_SCAN_20_DEGREE",
-    "XRAY_SCAN_30_DEGREE",
-    "XRAY_SCAN_min15_DEGREE",
+    "XRAY_SCAN_20DEG",
+    "XRAY_SCAN_30DEG",
+    "XRAY_SCAN_min15DEG",
     "THERMAL_CYCLING",
     "WIREBOND",
     "WIREBONDING",
     "ADC_CALIBRATION",
     "TUNING",
+    "TUNING_30DEG",
+    "TUNING_20DEG",
+    "TUNING_MINUS15DEG",
     "PARYLENE",
     "WP_ENVELOPE"
   ],
   "html":{
-    "OPTICAL": "viresult.html",
-    "MASS": "massresult.html",
-    "METROLOGY": "metresult.html",
-    "BACKSIDE_COPLANARITY": "coplanarity.html",
-    "FLATNESS": "coplanarity.html",
-    "GLUE_MODULE_FLEX_ATTACH":"glueattachresult.html",
-    "WIREBONDING":"wirebondingresult.html",
-    "WIREBOND":"pulltest.html",
-    "SENSOR_IV": "sensorIVresult.html",
-    "SENSOR_IV_min15_DEGREE": "sensorIVresult.html",
-    "SENSOR_IV_20_DEGREE": "sensorIVresult.html",
-    "SENSOR_IV_30_DEGREE": "sensorIVresult.html",
-    "SLDO_VI": "SLDOVIresult.html",
-    "XRAY_SCAN_min15_DEGREE": "xrayresult.html",
-    "XRAY_SCAN_20_DEGREE": "xrayresult.html",
-    "XRAY_SCAN_30_DEGREE": "xrayresult.html",
-    "RD53A_PULL-UP_RESISTOR": "pullupresult.html",
-    "IREFTRIM_FE": "irefresult.html",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST": "electrical.html",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST_30_DEGREE": "electrical.html",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST_20_DEGREE": "electrical.html",
-    "READOUT_IN_BASIC_ELECTRICAL_TEST_min15_DEGREE": "electrical.html",
-    "PIXEL_FAILURE_TEST": "electrical.html",
-    "PIXEL_FAILURE_TEST_30_DEGREE": "electrical.html",
-    "PIXEL_FAILURE_TEST_20_DEGREE": "electrical.html",
-    "PIXEL_FAILURE_TEST_min15_DEGREE": "electrical.html",
-    "ELECTRICAL_TEST": "electrical.html",
-    "WP_ENVELOPE": "wpenvelope_result.html",
-    "PARYLENE": "paryleneresult.html",
-    "THERMAL_CYCLING": "thermalresult.html",
-    "ADC_CALIBRATION": "adc_calibration.html",
-    "TUNING": "tuning.html"
+    "OPTICAL"						: "displayResults/viresult.html",
+    "MASS"						: "displayResults/massresult.html",
+    "METROLOGY"						: "displayResults/metresult.html",
+    "BACKSIDE_COPLANARITY"				: "displayResults/coplanarity.html",
+    "FLATNESS"						: "displayResults/coplanarity.html",
+    "GLUE_MODULE_FLEX_ATTACH"				: "displayResults/glueattachresult.html",
+    "WIREBONDING"					: "displayResults/wirebondingresult.html",
+    "WIREBOND"						: "displayResults/pulltest.html",
+    "SENSOR_IV"						: "displayResults/sensorIVresult.html",
+    "SENSOR_IV_MINUS15DEG"				: "displayResults/sensorIVresult.html",
+    "SENSOR_IV_20DEG"					: "displayResults/sensorIVresult.html",
+    "SENSOR_IV_30DEG"					: "displayResults/sensorIVresult.html",
+    "SLDO_VI"						: "displayResults/SLDOVIresult.html",
+    "XRAY_SCAN_MINUS15DEG"				: "displayResults/xrayresult.html",
+    "XRAY_SCAN_20DEG"					: "displayResults/xrayresult.html",
+    "XRAY_SCAN_30DEG"					: "displayResults/xrayresult.html",
+    "RD53A_PULL-UP_RESISTOR"				: "displayResults/pullupresult.html",
+    "IREFTRIM_FE"					: "displayResults/irefresult.html",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST"			: "displayResults/electrical.html",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST_30DEG"		: "displayResults/electrical.html",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST_20DEG"		: "displayResults/electrical.html",
+    "READOUT_IN_BASIC_ELECTRICAL_TEST_MINUS15DEG"	: "displayResults/electrical.html",
+    "PIXEL_FAILURE_TEST"				: "displayResults/electrical.html",
+    "PIXEL_FAILURE_TEST_30DEG"				: "displayResults/electrical.html",
+    "PIXEL_FAILURE_TEST_20DEG"				: "displayResults/electrical.html",
+    "PIXEL_FAILURE_TEST_MINUS15DEG"			: "displayResults/electrical.html",
+    "ELECTRICAL_TEST"					: "displayResults/electrical.html",
+    "WP_ENVELOPE"					: "displayResults/wpenvelope_result.html",
+    "PARYLENE"						: "displayResults/paryleneresult.html",
+    "THERMAL_CYCLING"					: "displayResults/thermalresult.html",
+    "ADC_CALIBRATION"					: "displayResults/adc_calibration.html",
+    "TUNING_30DEG"					: "displayResults/tuning.html",
+    "TUNING_20DEG"					: "displayResults/tuning.html",
+    "TUNING_MINUS15DEG"					: "displayResults/tuning.html"
   },
   "description":[
     "Visual Inspection (OPTICAL)",
diff --git a/viewer/pages/component.py b/viewer/pages/component.py
index 7c27a009..18a36cfc 100755
--- a/viewer/pages/component.py
+++ b/viewer/pages/component.py
@@ -1269,7 +1269,7 @@ def setQCResults(i_oid, i_col, i_tr_oid):
             analysis = {}
         results.update({"results":this_tr["results"]["scans"], "plots": plots, "analysis_result": analysis })
 
-    elif this_tr["testType"] == "SENSOR_IV" or this_tr["testType"] == "SENSOR_IV_min15_DEGREE" or this_tr["testType"] == "SENSOR_IV_20_DEGREE" or this_tr["testType"] == "SENSOR_IV_30_DEGREE":
+    elif "SENSOR_IV" in this_tr["testType"]:
         results.update({
           "results": this_tr["results"],
           "graph": SensorIV_graph(this_tr),
diff --git a/viewer/templates/displayResults/sensorIVresult.html b/viewer/templates/displayResults/sensorIVresult.html
index 29314cb8..fc3d1315 100644
--- a/viewer/templates/displayResults/sensorIVresult.html
+++ b/viewer/templates/displayResults/sensorIVresult.html
@@ -102,7 +102,8 @@ border: none;
             {% if keys!="unit" and keys!="Sensor_IV" %}
             <tr>
                 <th scope='raw' class='text-left'> {{ keys }} </td>
-                <td class='text-left'>{{ component['qctest']['results']['results'][keys] }} {{component['qctest']['results']['unit_list'][keys]}} </td>
+                <td class='text-left'>{{ component['qctest']['results']['results'][keys] }}</td>
+
             </tr>
             {% endif %}
             {% endfor %}
-- 
GitLab


From 90a6de9ea841e5b2047839d69cce93642ce0070a Mon Sep 17 00:00:00 2001
From: Hideyuki Oide <Hideyuki.Oide@cern.ch>
Date: Sun, 24 Jul 2022 17:50:59 +0900
Subject: [PATCH 7/7] reorganizing template html

---
 viewer/templates/#select_table.html#          | 166 ------------------
 viewer/templates/component.html               |  14 +-
 .../{ => displayComponent}/comment.html       |   0
 .../{ => displayComponent}/flow_image.html    |   0
 .../latest_test_index.html                    |   0
 .../moduleprop_index.html                     |   0
 .../{ => displayComponent}/qctest_index.html  |   0
 .../{ => displayComponent}/summary_index.html |   0
 .../{ => displayComponent}/test_index.html    |   0
 .../{ => displayResults}/orienresult.html     |   0
 .../templates/show_analysis_result.html.tmp   |  41 -----
 11 files changed, 7 insertions(+), 214 deletions(-)
 delete mode 100644 viewer/templates/#select_table.html#
 rename viewer/templates/{ => displayComponent}/comment.html (100%)
 rename viewer/templates/{ => displayComponent}/flow_image.html (100%)
 rename viewer/templates/{ => displayComponent}/latest_test_index.html (100%)
 rename viewer/templates/{ => displayComponent}/moduleprop_index.html (100%)
 rename viewer/templates/{ => displayComponent}/qctest_index.html (100%)
 rename viewer/templates/{ => displayComponent}/summary_index.html (100%)
 rename viewer/templates/{ => displayComponent}/test_index.html (100%)
 rename viewer/templates/{ => displayResults}/orienresult.html (100%)
 delete mode 100644 viewer/templates/show_analysis_result.html.tmp

diff --git a/viewer/templates/#select_table.html# b/viewer/templates/#select_table.html#
deleted file mode 100644
index 72ca65ca..00000000
--- a/viewer/templates/#select_table.html#
+++ /dev/null
@@ -1,166 +0,0 @@
-<div class="container">
-  <div class="row align-items-center justify-content-center">
-    <div class="col">
-
-    {% if not table_docs["text"] == '' %}
-      <p><div class="col-md-2"></div><div class="col-md-10"><font color=#ff0000>{{ table_docs["text"] }}</font></div></p>
-    {% endif %}
-
-      {% if table_docs['total']!=0 %}
-        <h5>Please select one result for each test items.</h5>
-        <form class="form-holizontal" role="form" method="post" action="{{ url_for('component_api.analyze_scan', id=table_docs['_id'], stage=table_docs['stage'], test=table_docs['test']) }}" accept-charset="UTF-8">
-        {% for scantype in table_docs["scans"]["scantypes"]%}
-        {% set outer_loop = loop %}
-        <h3><i class="fa fa-caret-right"></i>{{ scantype }}</h3>
-          {% if table_docs["pstage"] == "input" %}
-          <table class="table table-sm toppage" style="font-size: 10pt;">
-            <thead class="table-light">
-              <tr>
-                <th scope="col" rowspan=2>run Number</th>
-                <th scope="col" colspan=6>Test Data</th>
-                <th scope="col" colspan=1 rowspan=2>Tag</th>
-                <th scope="col" colspan=1 rowspan=2>Select</th>
-              </tr>
-              <tr>
-                <th scope="col">Stage</th>
-                <th scope="col">Test Type</th>
-                <th scope="col">User</th>
-                <th scope="col">Site</th>
-                <th scope="col">Date</th>
-                <th scope="col">Link</th>
-              </tr>
-            </thead>
-            <tbody>
-
-              {% for run_data in table_docs["run"] %}
-                {% if run_data['run_data']["testType"] == table_docs["scans"]["scantypes"][outer_loop.index0] %}
-                {% if run_data['run_data']['plots'] %}
-                <tr>
-                {% else %}
-                <tr style="background: #AABBCC;">
-                {% endif %}
-                    <td style="word-wrap:break-word;">{{ run_data['run_data']["runNumber"] }}</td>
-                    <td style="word-wrap:break-word;">{{ run_data['run_data']["stage"] }}</td>
-                    <td style="word-wrap:break-word;">{{ run_data['run_data']["testType"] }}</td>
-                    <td style="word-wrap:break-word;">{{ run_data['run_data']["user"] }}</td>
-                    <td style="word-wrap:break-word;">{{ run_data['run_data']["site"] }}</td>
-                    <td style="word-wrap:break-word;">{{ run_data['run_data']["datetime"] }}</td>
-                    <td style="word-wrap:break-word;">
-                      <a href="{{ url_for('component_api.show_component', runId=run_data['run_data']["_id"], collection='component', test='electrical', id='' ) }}">result page</a>
-                    </td>
-                    <td style="word-wrap:break-word;">
-                      {% for tag in run_data['run_data']['testRun_tag'] %}
-                        <div>{{ tag['name'] }}</div>
-                      {% endfor %}
-                    </td>
-                    <td style="word-wrap:break-word;">
-                      <div class="form-group row">
-                        <div class="col-md-10">
-                          <input type="radio" name="{{ scantype }}_id" value="{{ run_data['run_data']['_id'] }}" required="required">
-               		      </div>
-               		    </div>
-                    </td>
-                </tr>
-                {% endif %}
-              {% endfor %}
-            </tbody>
-          </table>
-
-          {% elif table_docs["pstage"] == "confirm" or table_docs["pstage"] == "edit" %}
-          <input type="hidden" value="{{ table_docs["run"][loop.index0]["_id"] }}" name="selectinfo">
-          <table class="table table-sm toppage" style="font-size: 10pt;">
-            <thead class="table-light">
-              <tr>
-                <th scope="col">Test Type</th>
-                <th scope="col">run Number</th>
-                <th scope="col">Test Date</th>
-                <th scope="col">Setting Temperature around Module Ntc</th>
-              </tr>
-            </thead>
-            <tbody>
-              <tr>
-                <td style="word-wrap:break-word;">{{ table_docs["run"][loop.index0]["testType"] }}</td>
-                <td style="word-wrap:break-word;">{{ table_docs["run"][loop.index0]["rn"] }}</td>
-                <td style="word-wrap:break-word;">{{ table_docs["run"][loop.index0]["time"] }}</td>
-                <td style="word-wrap:break-word;">{{ table_docs["run"][loop.index0]["temp"] }}</td>
-              </tr>
-            </tbody>
-          </table>
-
-          <div class="row align-items-center justify-content-flex-start">
-            <div class="col">
-            {% for result in table_docs["plots"][loop.index0]["results"] %}
-                <h4 style="font-size: 10pt;">
-                  <i class="fa fa-caret-right"></i> {{ result["mapType"] }}
-                  <a href="/localdb/plotData?testRunId={{ result['runId'] }}&mapType={{ result['mapType'] }}">plotly</a>
-                </h4>
-                <table class="table table-sm table-bordered" style="font-size: 8pt; table-layout: fixed;">
-                  <thead class="table-light">
-                    <tr>
-                      {% for chip, data in result["chips"].items() %}
-                        {% if not data["num"]==0 %}
-                          <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" width={{ data["length"] }} colspan={{ data["num"] }}>{{ chip }}</th>
-                        {% endif %}
-                      {% endfor %}
-                    </tr>
-                  </thead>
-                  <tbody>
-                    <tr>
-                      {% for chip, data in result["chips"].items() %}
-                        {% for plot in data["plots"] %}
-                          <td scope="col" class="text-left" style="word-wrap:break-word;">
-                          <a href={{ plot["url"] }} target="_brank" rel="noopener noreferrer">
-                            <img src={{ plot["url"] }} title={{ plot["name"] }} width={{ data["width"] }} height={{ data["width"] }}></img>
-                          </a>
-                          </td>
-                        {% endfor %}
-                      {% endfor %}
-                    </tr>
-                  </tbody>
-                </table>
-            {% endfor %}
-            </div>
-          </div>
-
-          {% endif %}
-        {% endfor %}
-
-        <br>
-        <br>
-        {% if table_docs["scans"]["analysis"]["run"] %}
-          {% if table_docs["pstage"] == "confirm" %}
-            <h3><i class="fa fa-caret-right"></i>Bad Pixel Analysis</h3>
-          {% endif %}
-          {% for chip_result in table_docs["scans"]["analysis_result"] %}
-            <h3>Chip: {{ chip_result['chipname'] }}</h3>
-            {% if table_docs["pstage"] == "confirm" and chip_result["tool"] == True %}
-
-              <h4 style="font-size: 12pt;">
-                {% if not chip_result["tool"] %}
-                <font color=#ff0000>### NO SOFTWARE ###</font>
-                {% endif %}
-              </h4>
-            {% include "show_analysis_result.html" %}
-            {% else %}
-              <font color=#ff0000> {{ table_docs }} </font>
-            {% endif %}
-          {% endfor %}
-        {% endif %}
-
-        <div class="col-md-12">
-        {% if table_docs["pstage"] == "input" %}
-          <button type="submit" class="btn btn-primary" name="pstage" value="confirm">Proceed</button><br />* After pushing the button the processing takes a few tens seconds; please wait.
-        {% elif table_docs["pstage"] == "confirm" %}
-          <button type="submit" class="btn btn-primary" name="pstage" value="scancomplete">Register</button>
-          <button type="submit" class="btn btn-primary" name="pstage" value="input">Back page</button>
-        {% elif table_docs["pstage"] == "edit" %}
-          <h3>Do you delete this commit ?</h3>
-          <button type="submit" class="btn btn-primary" name="pstage" value="delete">Delete</button>
-        {% endif %}
-        </div>
-        </form>
-
-      {% endif %}
-    </div>
-  </div>
-</div>
diff --git a/viewer/templates/component.html b/viewer/templates/component.html
index 11d70b1e..e9378f38 100644
--- a/viewer/templates/component.html
+++ b/viewer/templates/component.html
@@ -205,7 +205,7 @@ th { background-color: #eeeeff; }
         </div>
         <br>
         <div class="row align-items-top justify-content-left">
-          {% include "comment.html" %}
+          {% include "displayComponent/comment.html" %}
         </div>
 
 
@@ -276,13 +276,13 @@ th { background-color: #eeeeff; }
 	      {% if component['latest_tests'] %}
 	      <div style="margin-bottom: 50px;"></div>
 		  
-              {% include "latest_test_index.html" %}
+              {% include "displayComponent/latest_test_index.html" %}
 	      <div style="margin-bottom: 50px;"></div>
 	    
               {% endif %}
 	      
               {% if component['summary'] %}
-              {% include "summary_index.html" %}
+              {% include "displayComponent/summary_index.html" %}
               {% endif %}
 	      
 	      <div id="accordion">
@@ -290,20 +290,20 @@ th { background-color: #eeeeff; }
 	    <div style="margin-bottom: 50px;"></div>
 	    
             {% if component['property']['propIndex'] %}
-            {% include "moduleprop_index.html" %}
+            {% include "displayComponent/moduleprop_index.html" %}
             {% endif %}
 	    
 	    
             {% if component['qctest']['resultIndex'] %}
-            {% include "qctest_index.html" %}
+            {% include "displayComponent/qctest_index.html" %}
             {% endif %}
 
             {% if component['electrical']['resultIndex'] %}
-            {% include "test_index.html" %}
+            {% include "displayComponent/test_index.html" %}
             {% endif %}
 	    
 	    
-            {% include "flow_image.html" %}
+            {% include "displayComponent/flow_image.html" %}
 
 	    <!--div class="card">
 	      <div class="card-header" id="heading-supportedTests">
diff --git a/viewer/templates/comment.html b/viewer/templates/displayComponent/comment.html
similarity index 100%
rename from viewer/templates/comment.html
rename to viewer/templates/displayComponent/comment.html
diff --git a/viewer/templates/flow_image.html b/viewer/templates/displayComponent/flow_image.html
similarity index 100%
rename from viewer/templates/flow_image.html
rename to viewer/templates/displayComponent/flow_image.html
diff --git a/viewer/templates/latest_test_index.html b/viewer/templates/displayComponent/latest_test_index.html
similarity index 100%
rename from viewer/templates/latest_test_index.html
rename to viewer/templates/displayComponent/latest_test_index.html
diff --git a/viewer/templates/moduleprop_index.html b/viewer/templates/displayComponent/moduleprop_index.html
similarity index 100%
rename from viewer/templates/moduleprop_index.html
rename to viewer/templates/displayComponent/moduleprop_index.html
diff --git a/viewer/templates/qctest_index.html b/viewer/templates/displayComponent/qctest_index.html
similarity index 100%
rename from viewer/templates/qctest_index.html
rename to viewer/templates/displayComponent/qctest_index.html
diff --git a/viewer/templates/summary_index.html b/viewer/templates/displayComponent/summary_index.html
similarity index 100%
rename from viewer/templates/summary_index.html
rename to viewer/templates/displayComponent/summary_index.html
diff --git a/viewer/templates/test_index.html b/viewer/templates/displayComponent/test_index.html
similarity index 100%
rename from viewer/templates/test_index.html
rename to viewer/templates/displayComponent/test_index.html
diff --git a/viewer/templates/orienresult.html b/viewer/templates/displayResults/orienresult.html
similarity index 100%
rename from viewer/templates/orienresult.html
rename to viewer/templates/displayResults/orienresult.html
diff --git a/viewer/templates/show_analysis_result.html.tmp b/viewer/templates/show_analysis_result.html.tmp
deleted file mode 100644
index 1c0de6fc..00000000
--- a/viewer/templates/show_analysis_result.html.tmp
+++ /dev/null
@@ -1,41 +0,0 @@
-<br>
-<h4 style='font-size: 10pt;'>
-  <i class="fa fa-file"></i> Plot
-</h4>
-<table class="table table-sm table-bordered" style="font-size: 10pt;">
-  {% for step in chip_result['plot_info']  %}
-  <p>{{ step }}</p>
-  <thead class="table-light">
-    <tr>
-      <th ~~~ scope="col" class="text-left" style="word-wrap:break-word;" >{{ step["analysis"] }}</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      {% if 'map' in step['img'] %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ step['img']['map'] }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step['img']['map'] }}" title="{{ step["analysis"] }}" width=250 height=250 ></img>
-	</a>
-      </td>
-      {% endif %}
-      {% if 'proj' in step['img'] %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ step['img']['proj'] }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step['img']['proj'] }}" title="{{ step["analysis"] }}" width=250 height=250 ></img>
-	</a>
-      </td>
-      {% endif %}
-      {% if 'badpixels' in step['img'] %}
-      <td scope="col" class="text-left" style="word-wrap:break-word;">
-	<a href="{{ step['img']['badpixels'] }}" target="_brank" rel="noopener noreferrer">
-          <img src="{{ step['img']['badpixels'] }}" title="{{ step["analysis"] }}" width=250 height=250 ></img>
-	</a>
-      </td>
-      {% endif %}
-    </tr>
-  </tbody>
-  {% endfor %}
-</table>
-
-
-- 
GitLab