about summary refs log tree commit diff
path: root/gn2/wqflask/templates
diff options
context:
space:
mode:
Diffstat (limited to 'gn2/wqflask/templates')
-rw-r--r--gn2/wqflask/templates/base.html2
-rw-r--r--gn2/wqflask/templates/collections/list.html8
-rw-r--r--gn2/wqflask/templates/collections/view.html4
-rw-r--r--gn2/wqflask/templates/correlation_page.html4
-rw-r--r--gn2/wqflask/templates/dataset.html27
-rw-r--r--gn2/wqflask/templates/gnqa.html4
-rw-r--r--gn2/wqflask/templates/gnqa_answer.html33
-rw-r--r--gn2/wqflask/templates/gnqa_search_history.html46
-rw-r--r--gn2/wqflask/templates/gsearch_gene.html8
-rw-r--r--gn2/wqflask/templates/oauth2/confirm-resource-role-unassign-privilege.html34
-rw-r--r--gn2/wqflask/templates/oauth2/create-role.html42
-rw-r--r--gn2/wqflask/templates/oauth2/data-list-mrna.html2
-rw-r--r--gn2/wqflask/templates/oauth2/data-list-phenotype.html3
-rw-r--r--gn2/wqflask/templates/oauth2/profile_nav.html7
-rw-r--r--gn2/wqflask/templates/oauth2/view-group-role.html102
-rw-r--r--gn2/wqflask/templates/oauth2/view-resource-role.html149
-rw-r--r--gn2/wqflask/templates/oauth2/view-resource.html56
-rw-r--r--gn2/wqflask/templates/search-syntax.html24
-rw-r--r--gn2/wqflask/templates/search_result_page.html22
-rw-r--r--gn2/wqflask/templates/show_trait_transform_and_filter.html4
-rw-r--r--gn2/wqflask/templates/tool_buttons.html4
-rw-r--r--gn2/wqflask/templates/tutorials.html11
22 files changed, 369 insertions, 227 deletions
diff --git a/gn2/wqflask/templates/base.html b/gn2/wqflask/templates/base.html
index 26b75230..6c545646 100644
--- a/gn2/wqflask/templates/base.html
+++ b/gn2/wqflask/templates/base.html
@@ -188,7 +188,7 @@
 			</span>
 
 			<span  style="padding: 5px;margin-left: 65px;" >
-                            <a style="text-decoration: none" target="_blank" href="https://issues.genenetwork.org/topics/xapian/xapian-search-queries">
+                            <a style="text-decoration: none" target="_blank" href="/search-syntax">
                                 <i  style="text-align: center;color:#336699;;" class="fa fa-question-circle fa-2x" title="see more search hints" aria-hidden="true"></i>
                             </a>
 			</span>
diff --git a/gn2/wqflask/templates/collections/list.html b/gn2/wqflask/templates/collections/list.html
index c3d5d2a4..dc725fb6 100644
--- a/gn2/wqflask/templates/collections/list.html
+++ b/gn2/wqflask/templates/collections/list.html
@@ -57,8 +57,8 @@
                 <td align="center" style="padding: 0px;"><INPUT TYPE="checkbox" NAME="collection" class="checkbox trait_checkbox" VALUE="{{ uc.id }}"></td>
                 <td align="right">{{ loop.index }}
                 <td><a class="collection_name" href="{{ url_for('view_collection', uc_id=uc.id) }}">{{ uc.name }}</a></td>
-                <td>{{ uc.created_timestamp }}</td>
-                <td>{{ uc.changed_timestamp }}</td>
+                <td>{{ uc.created }}</td>
+                <td>{{ uc.changed }}</td>
                 <td align="right">{{ uc.num_members }}</td>
               </tr>
               {% endfor %}
@@ -88,8 +88,8 @@
               <td align="center" style="padding: 0px;"><INPUT TYPE="checkbox" NAME="collection" class="checkbox trait_checkbox" VALUE="{{ uc.id }}"></td>
               <td align="right">{{ loop.index }}
               <td><a class="collection_name" href="{{ url_for('view_collection', uc_id=uc.id) }}">{{ uc.name }}</a></td>
-              <td>{{ uc.created_timestamp }}</td>
-              <td>{{ uc.changed_timestamp }}</td>
+              <td>{{ uc.created }}</td>
+              <td>{{ uc.changed }}</td>
               <td align="right">{{ uc.num_members }}</td>
             </tr>
             {% endfor %}
diff --git a/gn2/wqflask/templates/collections/view.html b/gn2/wqflask/templates/collections/view.html
index 7e74442f..55669f09 100644
--- a/gn2/wqflask/templates/collections/view.html
+++ b/gn2/wqflask/templates/collections/view.html
@@ -214,9 +214,9 @@
                     'render': function(data) {
                         if (Object.hasOwn(data, 'description')){
                             try {
-                                return decodeURIComponent(escape(data.description))
+                                return decodeURIComponent(data.description)
                             } catch(err){
-                                return escape(data.description)
+                                return data.description
                             }
                         } else if (Object.hasOwn(data, 'location')){
                             return data.location
diff --git a/gn2/wqflask/templates/correlation_page.html b/gn2/wqflask/templates/correlation_page.html
index 24eaff1f..07118145 100644
--- a/gn2/wqflask/templates/correlation_page.html
+++ b/gn2/wqflask/templates/correlation_page.html
@@ -69,8 +69,8 @@
                 <input type="text" name="r_less_select" value="1.0" size="6" maxlength="10">, with mean >
                 <input type="text" name="mean_greater_select" value="0" size="6" maxlength="10">
                 <select id="mean_and_or" size="1">
-                    <option value="and" selected>AND</option>
-                    <option value="or">OR</option>
+                    <option value="and">AND</option>
+                    <option value="or" selected>OR</option>
                 </select>
                 mean <
                 <input type="text" name="mean_less_select" value="100" size="6" maxlength="10">
diff --git a/gn2/wqflask/templates/dataset.html b/gn2/wqflask/templates/dataset.html
index 096a3724..62fac650 100644
--- a/gn2/wqflask/templates/dataset.html
+++ b/gn2/wqflask/templates/dataset.html
@@ -40,31 +40,6 @@
  .panel-metadata dt::after {
      content: ":";
  }
-
- .search {
-     width: 50%;
-     margin: 1em auto;
- }
- .has-search .form-control-feedback {
-     right: initial;
-     left: 0;
-     color: #ccc;
- }
-
- .has-search .form-control {
-     padding-right: 12px;
-     padding-left: 34px;
- }
-
- .search {
-     transform: scale(1.5, 1.5);
- }
- .search input {
-     min-width: 17em;
- }
- .dataset-search {
-     padding: 0 17%;
- }
 </style>
 {% endblock %}
 
@@ -348,7 +323,7 @@
 </div>
 
 {% else %}
-<div class="container dataset-search">
+<div class="container">
     <p class="lead">We appreciate your interest, but unfortunately, we don't have any additional information available for: <strong>{{ name }}</strong>.  If you have other inquiries or need assistance with something else, please don't hesitate to get in touch with us.
 </div>
 
diff --git a/gn2/wqflask/templates/gnqa.html b/gn2/wqflask/templates/gnqa.html
index 8b50fe43..b3bc74fd 100644
--- a/gn2/wqflask/templates/gnqa.html
+++ b/gn2/wqflask/templates/gnqa.html
@@ -93,7 +93,7 @@
 	    AI Search
 	    <small>
 	      <sup>
-		<button class="search-hist-btn" hx-get="/gnqna/hist/" hx-target="#swap" hx-swap="innerHTML" >
+		<button class="search-hist-btn" hx-get="/gnqna/hist" hx-target="#swap" hx-swap="innerHTML">
 		  [Search History]
 		</button>
 	      </sup>
@@ -107,7 +107,7 @@
 	    <button class="btn btn-default btn-sm col-xs-1 col-sm-1 col-sm-offset-3"
 		    hx-post="/gnqna"
 		    hx-target="#swap"
-		    hx-swap="innerHTML"
+		    hx-swap="innerHTML"		  
 		    hx-indicator="#indicator">
 		<i class="fa fa-search fa-3x" aria-hidden="true" title="Search"></i>
 		<img id="indicator" class="htmx-indicator" src="/static/gif/loader.gif"/>
diff --git a/gn2/wqflask/templates/gnqa_answer.html b/gn2/wqflask/templates/gnqa_answer.html
index 0ddcfde7..41c1b338 100644
--- a/gn2/wqflask/templates/gnqa_answer.html
+++ b/gn2/wqflask/templates/gnqa_answer.html
@@ -3,10 +3,10 @@
     <div class="row container gnqa-answer" style="margin-bottom: 1em">
 	<p class="row lead">
 	    <mark style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif;"><b><i>{{ query }}</i></b></mark><br/>
-	    {{ answer }}
+	    {{ answer|safe }}
 	</p>
 	<div class="rating row" data-doc-id="{{query}}">
-	    <button class="btn" id="upvote" data-toggle="tooltip" data-placement="top" title="Vote Up"><i class="fa fa-thumbs-up fa-sm fa-1x" aria-hidden="true"></i></button>
+	    <button class="btn" id="upvote"  data-toggle="tooltip" data-placement="top" title="Vote Up"><i class="fa fa-thumbs-up fa-sm fa-1x" aria-hidden="true"></i></button>
             <button class="btn" id="downvote" data-toggle="tooltip" data-placement="top" title="Vote Down"><i class="fa fa-thumbs-down fa-sm fa-1x" aria-hidden="true"></i></button>
 	    <sub id="rate" class="text-info">	    
 	     </sub>
@@ -32,7 +32,7 @@
 			    </div>
 			    <div id="collapse{{reference.doc_id}}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading{{reference.doc_id}}">
 				<div class="panel-body">
-				    <p class="node-references">{{ reference.comboTxt }}</p>
+				    <p class="node-references">{{ reference.comboTxt|safe }}</p>
 				    <div>
 					{% if reference.pubmed %}
 					<details open>
@@ -60,7 +60,7 @@
 				</div>
 				<div id="collapse{{reference.doc_id}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{reference.doc_id}}">
 				    <div class="panel-body">
-					<p class="node-references">{{reference.comboTxt}}</p>
+					<p class="node-references">{{ reference.comboTxt|safe }}</p>
 				    <div>
 					{% if reference.pubmed %}
 					<details >
@@ -93,20 +93,27 @@
 {% block js %}
 
 <script>
+  function updateRatingHandler(target, responseObj, args){
+    let {status, response} = responseObj.xhr
+    if (status==200 && args == "upvote"){
+	  htmx.toggleClass(htmx.find('#upvote'), 'btn-success');
+	  htmx.removeClass(htmx.find("#downvote"), "btn-danger");
+      }
+      else if(status == 200 && args == "downvote") {
+          htmx.toggleClass(htmx.find('#downvote'), 'btn-danger');
+	  htmx.removeClass(htmx.find("#upvote"), "btn-success");
+      }
+      else {
+        alert(`Error occurred with status ${status} and Error ${response}` )
+}}
 var query = {{ query|tojson }};
 var answer = {{ answer|tojson }}
 var {task_id} = {{ task_id|tojson }}
-  htmx.on("#upvote", "click", function(evt){
+htmx.on("#upvote", "click", function(evt){
       vote_count = htmx.find(".btn-success") ? 0 : 1
-      htmx.ajax("POST", `/gnqna/rating/${task_id}/${vote_count}`, {target: "#rate", swap:"innerHTML",values: {'query': query, 'answer': answer}}).then(()=>{
-	  htmx.toggleClass(htmx.find('#upvote'), 'btn-success');
-	  htmx.removeClass(htmx.find("#downvote"), "btn-danger");
-})});
+    htmx.ajax("POST", `/gnqna/rating/${task_id}/${vote_count}`, {target: "#rate", handler: (target,obj)=> updateRatingHandler(target,obj,"upvote"), swap:"innerHTML",values: {'query': query, 'answer': answer}})});
   htmx.on("#downvote", "click", function(evt){
       vote_count = htmx.find(".btn-danger") ? 0 : -1
-      htmx.ajax("POST", `/gnqna/rating/${task_id}/${vote_count}`, {target: "#rate", swap:"innerHTML",values: {'query': query, 'answer': answer}}).then(()=>{
-      htmx.toggleClass(htmx.find('#downvote'), 'btn-danger');
-      htmx.removeClass(htmx.find("#upvote"), "btn-success")
-      })});
+      htmx.ajax("POST", `/gnqna/rating/${task_id}/${vote_count}`, {target: "#rate",handler: (target,obj)=> updateRatingHandler(target,obj,"downvote") , swap:"innerHTML",values: {'query': query, 'answer': answer}})});
 </script>
 {% endblock %}
diff --git a/gn2/wqflask/templates/gnqa_search_history.html b/gn2/wqflask/templates/gnqa_search_history.html
index 2c07b8c0..976fd7fd 100644
--- a/gn2/wqflask/templates/gnqa_search_history.html
+++ b/gn2/wqflask/templates/gnqa_search_history.html
@@ -1,42 +1,52 @@
-<section class="container-fluid  gnqa-copy">
+<section class="container-fluid  gnqa-copy" id="search-hist">
   <header class="row">
-
     <div class="panel panel default col-sm-6 col-sm-offset-3">
       <div class="panel panel-default">
 	<div class="panel-heading">
 	  <div>
-	    <h4 class="text-primary">You search History </h4>
+	    <h4 class="text-secondary" style="font-family: 'Linux Libertine','Georgia','Times','Source Serif Pro',serif;font-size:2.3rem">Your AI search History </h4>
 	  </div>
 	</div>
       </div>
     </div>
   </header>
   <div class="container row">
-  <div class="panel panel-default col-sm-6 col-sm-offset-3 ">
-    {% for record in prev_queries %}
-    <div class="panel-body">
-      <div class="row">
-	<input name="" type="checkbox" value="" class="col-sm-1">
+    <div>
+      <div class="col-sm-6 col-sm-offset-3" style="margin-bottom:10px">
+	<button type="button" class="btn btn-danger" id="delete-btn">Delete Selected </button>
+      </div>
+      <div >
+      <div class="panel panel-default col-sm-6 col-sm-offset-3 ">
+      <div>
+	<ul class="list-group list-group-flush" style="overflow-y:scroll">
+    {% for item in  prev_queries %}
+    <li class="row list-group-item">
+      	<input name="" type="checkbox"   value="{{item['task_id']}}" class="col-sm-1" style="height: 20px;
+  width: 20px;">
 	<div class="col-sm-10">
-	  {% for id,val in  record.items() %}
 	    <button
-	      hx-get="/gnqna/hist/search/{{id}}"
+	      hx-get="/gnqna/hist?query={{item['query']}}&search_term={{item['task_id']}}"
               hx-target="#swap"
 	      hx-swap="innerHTML"
 	      hx-trigger= "click"
 	      data-bs-toggle="tooltip"
 	      data-bs-placement="left"
-	      title="/gnqna/hist/search?{{id}}"
+	      title="/gnqna/hist?query={{item['query']}}&search_term={{item['task_id']}}"
 	      style="background:transparent;border:none;cursor:pointer"
 	      >
-	      <b class="text-info">{{val}} </b>
+	      <p class="text-info">{{item.get('query')}} </p>
 	    </button>
-	  {% endfor %}
-	</div>
-      </div>
-      </div>
-     {% endfor %}
+     </div>
+    </li>
+    {% endfor %}
+    </ul>
    </div>
   </div>
   </div>
- </section>
+</section>
+<script>
+  htmx.on("#delete-btn", "click", function(evt){
+      htmx.ajax("DELETE","/gnqna/hist", {target: "#search-hist","swap" :"outerHTML",
+				      values: Array.from(htmx.findAll("input[type=checkbox]:checked"), e => e.value)}) 
+  })
+</script>
diff --git a/gn2/wqflask/templates/gsearch_gene.html b/gn2/wqflask/templates/gsearch_gene.html
index 50b48401..3432662d 100644
--- a/gn2/wqflask/templates/gsearch_gene.html
+++ b/gn2/wqflask/templates/gsearch_gene.html
@@ -258,8 +258,12 @@
                 "scroller": true
                 {% endif %}
             }
-
-            create_table(tableId, traitsJson, columnDefs, tableSettings);
+            
+            if (traitsJson.length > 0) {
+              create_table(tableId, traitsJson, columnDefs, tableSettings);
+            } else {
+              $("#" + tableId +" td").replaceWith("<td>No data</td>")
+            }
 
         });
         
diff --git a/gn2/wqflask/templates/oauth2/confirm-resource-role-unassign-privilege.html b/gn2/wqflask/templates/oauth2/confirm-resource-role-unassign-privilege.html
new file mode 100644
index 00000000..988cf3b4
--- /dev/null
+++ b/gn2/wqflask/templates/oauth2/confirm-resource-role-unassign-privilege.html
@@ -0,0 +1,34 @@
+{%extends "base.html"%}
+{%from "oauth2/profile_nav.html" import profile_nav%}
+{%from "oauth2/display_error.html" import display_error%}
+{%block title%}View User{%endblock%}
+{%block content%}
+<div class="container">
+  {{profile_nav(uipages, user_privileges)}}
+  {{flash_me()}}
+
+  <form id="frm_confirm_resource_role_unassign_privilege"
+        method="POST"
+        action="{{url_for('oauth2.resource.unassign_privilege_from_resource_role',
+                resource_id=resource.resource_id,
+                role_id=role.role_id)}}">
+    <p>
+      Are you sure you want to unassign the privilege to
+      '{{privilege.privilege_description}}' from the role '{{role.role_name}}'
+      on resource '{{resource.resource_name}}'?</p>
+    <input type="hidden"
+           name="privilege_id"
+           value="{{privilege.privilege_id}}" />
+    
+    <input type="submit"
+           name="confirm"
+           value="Cancel"
+           class="btn btn-success" />
+
+    <input type="submit"
+           name="confirm"
+           value="Unassign"
+           class="btn btn-danger" />
+  </form>
+</div>
+{%endblock%}
diff --git a/gn2/wqflask/templates/oauth2/create-role.html b/gn2/wqflask/templates/oauth2/create-role.html
index f2bff7b4..6cf0bb78 100644
--- a/gn2/wqflask/templates/oauth2/create-role.html
+++ b/gn2/wqflask/templates/oauth2/create-role.html
@@ -7,31 +7,43 @@
   {{profile_nav("roles", user_privileges)}}
   <h3>Create Role</h3>
 
-  {{flash_me()}}
+  <p>Create a new role to act on resource "{{resource.resource_name}}"</p>
 
-  {%if group_privileges_error is defined%}
-  {{display_error("Group Privileges", group_privileges_error)}}
+  {%if resource_role_error is defined%}
+  {{display_error("Resource Role", resource_role_error)}}
   {%else%}
-  {%if "group:role:create-role" in user_privileges%}
-  <form method="POST" action="{{url_for('oauth2.role.create_role')}}">
-    <legend>Create Group Role</legend>
+  {%if "resource:role:create-role" in (user_privileges|map(attribute="privilege_id")) %}
+  <form method="POST" action="{{url_for('oauth2.resource.create_resource_role',
+                              resource_id=resource.resource_id)}}">
+    <legend>create resource role</legend>
+
+    {{flash_me()}}
+
     <div class="form-group">
       <label for="role_name" class="form-label">Name</label>
-      <input type="text" id="role_name" name="role_name" required="required"
-	     class="form-control"
-	     {%if prev_role_name is defined and prev_role_name is not none%}
-	     value="{{prev_role_name}}"
-	     {%endif%} />
+      <div class="input-group">
+        <span class="input-group-addon">
+          {{resource.resource_name|replace(" ", "_")}}::
+        </span>
+        <input type="text" id="role_name" name="role_name" required="required"
+	       class="form-control"
+	       {%if prev_role_name is defined and prev_role_name is not none%}
+	       value="{{prev_role_name}}"
+	       {%endif%} />
+      </div>
+      <span class="form-text text-muted">
+        The name of the role will have the resource's name appended.
+      </span>
     </div>
     <label class="form-label">Privileges</label>
-    {%for priv in group_privileges%}
+    {%for priv in user_privileges%}
     <div class="checkbox">
-      <label for="chk:{{priv.privilege_id}}">
-	<input type="checkbox" id="chk:{{priv.privilege_id}}"
+      <label for="chk-{{priv.privilege_id}}">
+	<input type="checkbox" id="chk-{{priv.privilege_id}}"
 	       name="privileges[]" value={{priv.privilege_id}} />
 	<span style="text-transform: capitalize;">
 	  {{priv.privilege_description}}
-	</span> ({{priv.privilege_id}})
+	</span>
       </label>
     </div>
     {%endfor%}
diff --git a/gn2/wqflask/templates/oauth2/data-list-mrna.html b/gn2/wqflask/templates/oauth2/data-list-mrna.html
index 728e95d4..c5c1c27e 100644
--- a/gn2/wqflask/templates/oauth2/data-list-mrna.html
+++ b/gn2/wqflask/templates/oauth2/data-list-mrna.html
@@ -92,7 +92,7 @@
   <div class="row">
     <span id="search-messages" class="alert-danger" style="display:none"></span>
     <form id="frm-search"
-	  action="{{search_uri}}"
+	  action="{{url_for('oauth2.data.json_search_mrna')}}"
 	  method="POST">
       <legend>Search: mRNA Assay</legend>
       <input type="hidden" value="{{species_name}}" name="species"
diff --git a/gn2/wqflask/templates/oauth2/data-list-phenotype.html b/gn2/wqflask/templates/oauth2/data-list-phenotype.html
index e5172c70..d355f3f9 100644
--- a/gn2/wqflask/templates/oauth2/data-list-phenotype.html
+++ b/gn2/wqflask/templates/oauth2/data-list-phenotype.html
@@ -113,7 +113,8 @@
     <form id="frm-search-traits"
 	  action="#"
 	  method="POST"
-	  data-gn-server-url="{{gn_server_url}}">
+          data-search-endpoint="{{search_endpoint}}"
+          data-pheno-results-template="{{pheno_results_template}}">
       {%if dataset_type == "mrna"%}
       <legend>mRNA: Search</legend>
       {%else%}
diff --git a/gn2/wqflask/templates/oauth2/profile_nav.html b/gn2/wqflask/templates/oauth2/profile_nav.html
index aa752905..c79bccbc 100644
--- a/gn2/wqflask/templates/oauth2/profile_nav.html
+++ b/gn2/wqflask/templates/oauth2/profile_nav.html
@@ -17,13 +17,6 @@
   </li>
 
   <li role="presentation"
-      {%if calling_page == "roles"%}
-      class="active"
-      {%endif%}>
-    <a href="{{url_for('oauth2.role.user_roles')}}">Roles</a>
-  </li>
-
-  <li role="presentation"
       {%if calling_page == "resources"%}
       class="active"
       {%endif%}>
diff --git a/gn2/wqflask/templates/oauth2/view-group-role.html b/gn2/wqflask/templates/oauth2/view-group-role.html
deleted file mode 100644
index 5da023bf..00000000
--- a/gn2/wqflask/templates/oauth2/view-group-role.html
+++ /dev/null
@@ -1,102 +0,0 @@
-{%extends "base.html"%}
-{%from "oauth2/profile_nav.html" import profile_nav%}
-{%from "oauth2/display_error.html" import display_error%}
-{%block title%}View User{%endblock%}
-{%block content%}
-<div class="container" style="min-width: 1250px;">
-  {{profile_nav("roles", user_privileges)}}
-  <h3>View Group Role</h3>
-
-  {{flash_me()}}
-
-  <div class="container-fluid">
-    <div class="row">
-      <h3>Role Details</h3>
-      {%if group_role_error is defined%}
-      {{display_error("Group Role", group_role_error)}}
-      {%else%}
-      <table class="table">
-	<caption>Details for '{{group_role.role.role_name}}' Role</caption>
-	<thead>
-	  <tr>
-	    <th>Privilege</th>
-	    <th>Description</th>
-	    <th>Action</th>
-	  </tr>
-	</thead>
-	<tbody>
-	  {%for privilege in group_role.role.privileges%}
-	  <tr>
-	    <td>{{privilege.privilege_id}}</td>
-	    <td>{{privilege.privilege_description}}</td>
-	    <td>
-	      <form action="{{url_for(
-			    'oauth2.group.delete_privilege_from_role',
-			    group_role_id=group_role.group_role_id)}}"
-		    method="POST">
-		<input type="hidden" name="privilege_id"
-		       value="{{privilege.privilege_id}}" />
-		<input type="submit" class="btn btn-danger"
-		       value="Remove"
-		       {%if not group_role.role.user_editable%}
-		       disabled="disabled"
-		       {%endif%} />
-	      </form>
-	    </td>
-	  </tr>
-	  {%endfor%}
-	</tbody>
-      </table>
-      {%endif%}
-    </div>
-
-    <div class="row">
-      <h3>Other Privileges</h3>
-      <table class="table">
-	<caption>Other Privileges not Assigned to this Role</caption>
-	<thead>
-	  <tr>
-	    <th>Privilege</th>
-	    <th>Description</th>
-	    <th>Action</th>
-	  </tr>
-	</thead>
-
-	<tbody>
-	  {%for priv in group_privileges%}
-	  <tr>
-	    <td>{{priv.privilege_id}}</td>
-	    <td>{{priv.privilege_description}}</td>
-	    <td>
-	      <form action="{{url_for(
-			    'oauth2.group.add_privilege_to_role',
-			    group_role_id=group_role.group_role_id)}}"
-		    method="POST">
-		<input type="hidden" name="privilege_id"
-		       value="{{priv.privilege_id}}" />
-		<input type="submit" class="btn btn-warning"
-		       value="Add to Role"
-		       {%if not group_role.role.user_editable%}
-		       disabled="disabled"
-		       {%endif%} />
-	      </form>
-	    </td>
-	  </tr>
-	  {%else%}
-	  <tr>
-	    <td colspan="3">
-	      <span class="glyphicon glyphicon-info-sign text-info">
-	      </span>
-	      &nbsp;
-	      <span class="text-info">All privileges assigned!</span>
-	    </td>
-	  </tr>
-	  {%endfor%}
-	</tbody>
-      </table>
-    </div>
-
-  </div>
-
-</div>
-{%endblock%}
diff --git a/gn2/wqflask/templates/oauth2/view-resource-role.html b/gn2/wqflask/templates/oauth2/view-resource-role.html
new file mode 100644
index 00000000..4bd0ab45
--- /dev/null
+++ b/gn2/wqflask/templates/oauth2/view-resource-role.html
@@ -0,0 +1,149 @@
+{%extends "base.html"%}
+{%from "oauth2/profile_nav.html" import profile_nav%}
+{%from "oauth2/display_error.html" import display_error%}
+{%block title%}View User{%endblock%}
+{%block content%}
+
+{%macro unassign_button(resource_id, role_id, privilege_id)%}
+<form method="GET"
+      action="{{url_for('oauth2.resource.unassign_privilege_from_resource_role',
+              resource_id=resource_id,
+              role_id=role_id)}}"
+      id="frm_unlink_privilege_{{privilege_id}}">
+  <input type="hidden" name="resource_id" value="{{resource_id}}" />
+  <input type="hidden" name="role_id" value="{{role_id}}" />
+  <input type="hidden" name="privilege_id" value="{{privilege_id}}" />
+  <input type="submit" value="Unassign" class="btn btn-danger" />
+</form>
+{%endmacro%}
+
+<div class="container">
+  <div class="row">
+    {{profile_nav(uipages, user_privileges)}}
+    {{flash_me()}}
+    {%if resource_error is defined%}
+    {{display_error("Resource", resource_error)}}
+    {%else%}
+    <h3>Role for Resource '{{resource.resource_name}}'</h3>
+    {%if role_error is defined%}
+    {{display_error("Role", role_error)}}
+    {%else%}
+    <table class="table">
+      <caption>Role '{{role.role_name}}' for resource '{{resource.resource_name}}'</caption>
+      <thead>
+        <tr>
+          <th>Role Name</th>
+          <th>Privilege</th>
+          <th>Action</th>
+        </tr>
+      </thead>
+
+      <tbody>
+        {%for priv in role.privileges%}
+        {%if loop.index0 == 0%}
+        <tr>
+          <td rowspan="{{role.privileges | length}}"
+              style="text-align: center;vertical-align: middle;">
+            {{role.role_name}}</td>
+          <td>{{priv.privilege_description}}</td>
+          <td>{{unassign_button(resource.resource_id, role.role_id, priv.privilege_id)}}</td>
+        </tr>
+        {%else%}
+        <tr>
+          <td>{{priv.privilege_description}}</td>
+          <td>{{unassign_button(resource.resource_id, role.role_id, priv.privilege_id)}}</td>
+        </tr>
+        {%endif%}
+        {%else%}
+        <tr>
+          <td colspan="3">
+            <p class="text-info">
+              <span class="glyphicon glyphicon-info-sign text-info"></span>
+              &nbsp;
+              This role has no privileges.
+            </p>
+          </td>
+        </tr>
+        {%endfor%}
+      </tbody>
+    </table>
+  </div>
+
+  <div class="row">
+    <form id="frm_assign_privileges" method="POST" action="#">
+      <input type="hidden" name="resource_id" value="{{resource_id}}" />
+      <input type="hidden" name="role_id" value="{{role_id}}" />
+      {%if unassigned_privileges | length == 0%}
+      <p class="text-info">
+        <strong>{{title}}</strong>:
+        <span class="glyphicon glyphicon-info-sign text-info"></span>
+        &nbsp;
+        There are no more privileges left to assign.
+      </p>
+      {%else%}
+      <fieldset>
+        <legend>Select privileges to assign to this role</legend>
+        {%for priv in unassigned_privileges%}
+        <div class="checkbox">
+          <label for="rdo_{{priv.privilege_id}}">
+            <input type="checkbox" value="{{priv.privilege_id}}" />
+            {{priv.privilege_description}}
+          </label>
+        </div>
+        {%endfor%}
+      </fieldset>
+
+      <input type="submit" class="btn btn-primary" value="Assign" />
+      {%endif%}
+    </form>
+  </div>
+
+  {%if user_error is defined%}
+  {{display_error("Users", user_error)}}
+  {%endif%}
+
+  {%if users is defined and users | length > 0%}
+  <div class="row">
+    <h3>Users</h3>
+
+    <table class="table">
+      <caption>
+        Users assigned role '{{role.role_name}}' on resource
+        '{{resource.resource_name}}'
+      </caption>
+
+      <thead>
+        <tr>
+          <th>Email</th>
+          <th>Name</th>
+        </tr>
+      </thead>
+
+      <tbody>
+        {%for user in users%}
+        <tr>
+          <td>{{user.email}}</td>
+          <td>{{user.name}}</td>
+        </tr>
+        {%endfor%}
+        </tbody>
+    </table>
+  </div>
+  {%endif%}
+
+  {%if users is defined and users | length == 0%}
+  <div class="row">
+    <h3>Delete this role</h3>
+    <p class="text-danger">
+      <strong>Delete Role</strong>:
+      <span class="glyphicon glyphicon-exclamation-sign text-danger"></span>
+      &nbsp;
+      This will delete this role, and you will no longer have access to it.
+    </p>
+  </div>
+  {%endif%}
+  {%endif%}
+  {%endif%}
+</div>
+
+{%endblock%}
diff --git a/gn2/wqflask/templates/oauth2/view-resource.html b/gn2/wqflask/templates/oauth2/view-resource.html
index 275fcb24..0788e30c 100644
--- a/gn2/wqflask/templates/oauth2/view-resource.html
+++ b/gn2/wqflask/templates/oauth2/view-resource.html
@@ -2,6 +2,10 @@
 {%from "oauth2/profile_nav.html" import profile_nav%}
 {%from "oauth2/display_error.html" import display_error%}
 {%block title%}View User{%endblock%}
+{%block css%}
+<link rel="stylesheet" href="/static/new/css/pills.css" />
+<link rel="stylesheet" href="/static/new/css/resource-roles.css" />
+{%endblock%}
 {%block content%}
 <div class="container" style="min-width: 1250px;">
   {{profile_nav("resources", user_privileges)}}
@@ -230,7 +234,27 @@
     </div>
 
     <div class="row">
-      <h3>User Roles</h3>
+      <h3>Available Resource Roles</h3>
+      <div class="resource_roles">
+        {%for role in resource_roles%}
+        <a class="pill"
+           href="{{url_for('oauth2.resource.view_resource_role',
+                 resource_id=resource.resource_id,
+                 role_id=role.role_id)}}"
+           title="Role page for role named '{{role.role_name}}'">
+          {{role.role_name}}
+        </a>
+        {%endfor%}
+      </div>
+      <hr />
+      <a title="create a new role for this resource"
+         href="{{url_for('oauth2.resource.create_resource_role',
+               resource_id=resource.resource_id)}}"
+         class="btn btn-info">New Role</a>
+    </div>
+
+    <div class="row">
+      <h3>Users: Assigned Roles</h3>
       {%if users_n_roles_error is defined%}
       {{display_error("Users and Roles", users_n_roles_error)}}
       {%else%}
@@ -254,14 +278,14 @@
 	    <th>Role</th>
 	    <th>Action</th>
 	  </tr>
-	  {%for grole in user_row.roles%}
+	  {%for role in user_row.roles%}
 	  <tr>
 	    <td>
 	      <a href="{{url_for(
 		       'oauth2.role.role',
-		       role_id=grole.role_id)}}"
-		 title="Details for '{{grole.role_name}}' role">
-		{{grole.role_name}}
+		       role_id=role.role_id)}}"
+		 title="Details for '{{role.role_name}}' role">
+		{{role.role_name}}
 	      </a>
 	    </td>
 	    <td>
@@ -270,8 +294,8 @@
 		    method="POST">
 		<input type="hidden" name="user_id"
 		       value="{{user_row.user.user_id}}" />
-		<input type="hidden" name="group_role_id"
-		       value="{{grole.group_role_id}}">
+		<input type="hidden" name="role_id"
+		       value="{{role.role_id}}">
 		<input type="submit"
 		       value="Unassign"
 		       class="btn btn-danger"
@@ -301,8 +325,8 @@
 
     <div class="row">
       <h3>Assign</h3>
-      {%if group_roles_error is defined%}
-      {{display_error("Group Roles", group_roles_error)}}
+      {%if resource_roles_error is defined%}
+      {{display_error("Resource Roles", resource_roles_error)}}
       {%elif users_error is defined%}
       {{display_error("Users", users_error)}}
       {%else%}
@@ -312,13 +336,13 @@
 	    method="POST" autocomplete="off">
 	<input type="hidden" name="resource_id" value="{{resource_id}}" />
 	<div class="form-group">
-	  <label for="group_role_id" class="form-label">Role</label>
-	  <select class="form-control" name="group_role_id"
-		  id="group_role_id" required="required">
-	    <option value="">Select role</option>
-	    {%for grole in group_roles%}
-	    <option value="{{grole.group_role_id}}">
-	      {{grole.role.role_name}}
+	  <label for="role_id" class="form-label">Role</label>
+	  <select class="form-control" name="role_id"
+		  id="role_id" required="required">
+	    <option value="">Select role</option>>
+	    {%for rrole in resource_roles%}
+	    <option value="{{rrole.role_id}}">
+	      {{rrole.role_name}}
 	    </option>
 	    {%endfor%}
 	  </select>
diff --git a/gn2/wqflask/templates/search-syntax.html b/gn2/wqflask/templates/search-syntax.html
new file mode 100644
index 00000000..52538826
--- /dev/null
+++ b/gn2/wqflask/templates/search-syntax.html
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+
+{% block title %}Global Search Syntax{% endblock %}
+
+{% block css %}
+<link rel="stylesheet" type="text/css" href="/static/new/css/markdown.css" />
+{% endblock %}
+
+{% block content %}
+
+ <div class="github-btn-container">
+    <div class="github-btn">
+        <a href="https://github.com/genenetwork/gn-docs/blob/master/general/search/xapian_syntax.md">
+            Edit Text
+            <img src="/static/images/edit.png">
+        </a>
+    </div>
+</div>
+<div id="markdown" class="container">
+   {{ rendered_markdown|safe }}
+
+</div>
+
+{% endblock %}
\ No newline at end of file
diff --git a/gn2/wqflask/templates/search_result_page.html b/gn2/wqflask/templates/search_result_page.html
index 934b6a9d..fccda1ae 100644
--- a/gn2/wqflask/templates/search_result_page.html
+++ b/gn2/wqflask/templates/search_result_page.html
@@ -224,7 +224,8 @@
               'type': "natural",
               'width': "{{ max_widths.symbol * 8 }}px",
               'targets': 3,
-              'data': "symbol"
+              'data': "symbol",
+              'defaultContent': "N/A"
             },
             {
               'title': "Description",
@@ -237,9 +238,9 @@
                   description = data.description.slice(0, 200) + '...'
                 }
                 try {
-                  return decodeURIComponent(escape(description))
+                  return decodeURIComponent(description)
                 } catch(err){
-                  return escape(description)
+                  return description
                 }
               }
             },
@@ -248,14 +249,16 @@
               'type': "natural-minus-na",
               'width': "130px",
               'targets': 5,
-              'data': "location"
+              'data': "location",
+              'defaultContent': "N/A"
             },
             {
               'title': "<div style='text-align: right;'>Mean</div>",
               'type': "natural-minus-na",
               'width': "40px",
-              'data': "mean",
               'targets': 6,
+              'data': "mean",
+              'defaultContent': "N/A",
               'orderSequence': [ "desc", "asc"]
             },
             {
@@ -279,6 +282,7 @@
               'data': "additive",
               'width': "65px",
               'targets': 9,
+              'defaultContent': "N/A",
               'orderSequence': [ "desc", "asc"]
             }{% elif dataset.type == 'Publish' %},
             {
@@ -294,6 +298,7 @@
             {
               'title': "Description",
               'type': "natural",
+              'width': "500px",
               'data': null,
               'targets': 3,
               'render': function(data) {
@@ -302,9 +307,9 @@
                   description = data.description.slice(0, 200) + '...'
                 }
                 try {
-                  return decodeURIComponent(escape(description))
+                  return decodeURIComponent(description)
                 } catch(err){
-                  return escape(description)
+                  return description
                 }
               }
             },
@@ -312,8 +317,9 @@
               'title': "<div style='text-align: right;'>Mean</div>",
               'type': "natural-minus-na",
               'width': "60px",
-              'data': "mean",
               'targets': 4,
+              'data': "mean",
+              'defaultContent': "N/A",
               'orderSequence': [ "desc", "asc"]
             },
             {
diff --git a/gn2/wqflask/templates/show_trait_transform_and_filter.html b/gn2/wqflask/templates/show_trait_transform_and_filter.html
index e61e1248..8a7cd8a5 100644
--- a/gn2/wqflask/templates/show_trait_transform_and_filter.html
+++ b/gn2/wqflask/templates/show_trait_transform_and_filter.html
@@ -5,7 +5,7 @@
         needed.
     </p>
     <div id="blockMenuSpan" class="input-append block-div">
-        <label for="remove_samples_field">Block samples by index:</label>
+        <label for="remove_samples_field">Filter samples by index:</label>
         <input type="text" id="remove_samples_field" placeholder="Example: 3, 5-10, 12">
         <select id="block_group" size="1">
           <option value="primary">
@@ -23,7 +23,7 @@
     </div>
     {% if categorical_attr_exists == "true" %}
     <div class="input-append block-div-2">
-        <label for="exclude_column">Block samples by group:</label>
+        <label for="exclude_column">Filter samples by group:</label>
         <select id="exclude_column" size=1>
           {% for attribute in sample_groups[0].attributes %}
           {% if sample_groups[0].attributes[attribute].distinct_values|length <= 500 and sample_groups[0].attributes[attribute].distinct_values|length > 1 %}
diff --git a/gn2/wqflask/templates/tool_buttons.html b/gn2/wqflask/templates/tool_buttons.html
index c6d1476c..3e716d70 100644
--- a/gn2/wqflask/templates/tool_buttons.html
+++ b/gn2/wqflask/templates/tool_buttons.html
@@ -18,6 +18,10 @@
   BNW
 </button>
 
+<button id="send_to_genecup" class="btn btn-primary submit_special" data-url="/genecup" >
+  GeneCup
+</button>
+
 <button id="wgcna_setup" class="btn btn-primary submit_special" data-url="/wgcna_setup" title="WGCNA Analysis" >
     WGCNA
 </button>
diff --git a/gn2/wqflask/templates/tutorials.html b/gn2/wqflask/templates/tutorials.html
index 870dba1a..6281291f 100644
--- a/gn2/wqflask/templates/tutorials.html
+++ b/gn2/wqflask/templates/tutorials.html
@@ -221,11 +221,12 @@ $('#myTable3').dataTable( {
         </tr>
         </thead>
         <tbody>
-        <tr><td><a href="https://www.biorxiv.org/content/10.1101/2020.12.23.424047v1">GeneNetwork: a continuously updated tool for systems genetics analyses</a></td></tr>
-        <tr><td><a href="https://doi.org/10.3390/genes13040614">New Insights on Gene by Environmental Effects of Drugs of Abuse in Animal Models Using GeneNetwork</a></td>
-        <tr><td><a href="https://www.opar.io/pdf/Rat_HRDP_Brain_Proteomics_Wang_WIlliams_08Oct2021.pdf">A Primer on Brain Proteomics and protein-QTL Analysis for Substance Use Disorders</a></td></tr>
-        
-                </tbody>
+            <tr><td><a href="https://www.opar.io/pdf/Ashbrook_ExperimentalPrecisionMedicineMouseModels_2023.pdf">Experimental precision medicine: Mouse models in which to test precision medicine</a></td>
+            <tr><td><a href="https://www.opar.io/pdf/Williams_ResourcesForSystemsGenetics_2017.pdf">Systems Genetics. Methods and Protocols</a></td></tr>
+            <tr><td><a href="https://www.biorxiv.org/content/10.1101/2020.12.23.424047v1">GeneNetwork: a continuously updated tool for systems genetics analyses</a></td></tr>
+            <tr><td><a href="https://doi.org/10.3390/genes13040614">New Insights on Gene by Environmental Effects of Drugs of Abuse in Animal Models Using GeneNetwork</a></td>
+            <tr><td><a href="https://www.opar.io/pdf/Rat_HRDP_Brain_Proteomics_Wang_WIlliams_08Oct2021.pdf">A Primer on Brain Proteomics and protein-QTL Analysis for Substance Use Disorders</a></td></tr>
+        </tbody>
     </table>
         <script>
 $('#myTable4').dataTable( {