Skip to content

Commit 22156ed

Browse files
josenavasantgonza
authored andcommitted
Analysis refactor GUI part2 (#2077)
* fix #1505 * improving some GUI stuff * improving some GUI stuff - missing lines * addressing all comments * ready for review * fix #1987 * initial commit * requested changes * fix filter job list * Fixing server cert (#2051) * fix get_studies * flake8 * fix #503 * fix #2010 * fix #1913 * fix errors * addressing @josenavas comment * flake8 * fix #1010 * fix #1066 (#2058) * addressing @josenavas comments * fix #1961 * fix #1837 * Automatic jobs & new stats (#2057) * fix #814, fix #1636 * fixing error in test-env * fixing stats.html call * adding img * addressing @josenavas comments * rm for loops * addresssing @ElDeveloper comments * generalizing this functionality * fix #1816 * fix #1959 * addressing @josenavas comments * addressing @josenavas comments * fixing error * fixed? * addressing @josenavas comments * addressing @wasade comments * fix flake8 * generate biom and metadata release (#2066) * initial commit * adding portal * addressing @josenavas comments * pid -> qiita_artifact_id * addressing @josenavas comments * addressing @ElDeveloper comments * rm 50.sql * database changes to fix 969 * adding delete * addressing @josenavas comments * addressing @ElDeveloper comments * duh! * fix generate_biom_and_metadata_release (#2072) * fix generate_biom_and_metadata_release * addressing @ElDeveloper comment * Removing qiita ware code that will not be used anymore * Organizing the handlers and new analysis description page * Connecting the analysis creation and making interface responsive * Addressing @antgonza's comments * Removing unused code
1 parent a083e23 commit 22156ed

File tree

6 files changed

+156
-39
lines changed

6 files changed

+156
-39
lines changed

qiita_pet/handlers/analysis_handlers/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
from .util import check_analysis_access
1010
from .base_handlers import (CreateAnalysisHandler, AnalysisDescriptionHandler,
11-
AnalysisGraphHandler)
11+
AnalysisGraphHandler, AnalysisJobsHandler)
1212
from .listing_handlers import (ListAnalysesHandler, AnalysisSummaryAJAX,
1313
SelectedSamplesHandler)
1414

1515
__all__ = ['CreateAnalysisHandler', 'AnalysisDescriptionHandler',
16-
'AnalysisGraphHandler', 'ListAnalysesHandler',
17-
'AnalysisSummaryAJAX', 'SelectedSamplesHandler',
18-
'check_analysis_access']
16+
'AnalysisGraphHandler', 'AnalysisJobsHandler',
17+
'ListAnalysesHandler', 'AnalysisSummaryAJAX',
18+
'SelectedSamplesHandler', 'check_analysis_access']

qiita_pet/handlers/analysis_handlers/base_handlers.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,41 @@ def analyisis_graph_handler_get_request(analysis_id, user):
9898
class AnalysisGraphHandler(BaseHandler):
9999
@authenticated
100100
@execute_as_transaction
101-
def get(self):
102-
analysis_id = to_int(self.get_argument('analysis_id'))
101+
def get(self, analysis_id):
102+
analysis_id = to_int(analysis_id)
103103
response = analyisis_graph_handler_get_request(
104104
analysis_id, self.current_user)
105105
self.write(response)
106+
107+
108+
def analyisis_job_handler_get_request(analysis_id, user):
109+
"""Returns the job information of the analysis
110+
111+
Parameters
112+
----------
113+
analysis_id: int
114+
The analysis id
115+
user : qiita_db.user.User
116+
The user performing the request
117+
118+
Returns
119+
-------
120+
dict with the jobs information
121+
"""
122+
analysis = Analysis(analysis_id)
123+
# Check if the user actually has access to the analysis
124+
check_analysis_access(user, analysis)
125+
return {
126+
j.id: {'status': j.status, 'step': j.step,
127+
'error': j.log.msg if j.log else ""}
128+
for j in analysis.jobs}
129+
130+
131+
class AnalysisJobsHandler(BaseHandler):
132+
@authenticated
133+
@execute_as_transaction
134+
def get(self, analysis_id):
135+
analysis_id = to_int(analysis_id)
136+
response = analyisis_job_handler_get_request(
137+
analysis_id, self.current_user)
138+
self.write(response)

qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ def test_analyisis_graph_handler_get_request(self):
5151

5252
class TestBaseHandlers(TestHandlerBase):
5353
def test_post_create_analysis_handler(self):
54+
user = User('test@foo.bar')
55+
dflt_analysis = user.default_analysis
56+
dflt_analysis.add_samples(
57+
{4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
58+
'1.SKM9.640192', '1.SKM4.640180']})
5459
args = {'name': 'New Test Analysis',
5560
'description': 'Test Analysis Description'}
5661
response = self.post('/analysis/create/', args)
@@ -64,7 +69,7 @@ def test_get_analysis_description_handler(self):
6469
self.assertEqual(response.code, 200)
6570

6671
def test_get_analysis_graph_handler(self):
67-
response = self.get('/analysis/description/graph/', {'analysis_id': 1})
72+
response = self.get('/analysis/description/1/graph/')
6873
self.assertEqual(response.code, 200)
6974
# The job id is randomly generated in the test environment. Gather
7075
# it here. There is only 1 job in the first artifact of the analysis
@@ -78,6 +83,23 @@ def test_get_analysis_graph_handler(self):
7883
self.assertItemsEqual(obs['edges'], exp['edges'])
7984
self.assertItemsEqual(obs['nodes'], exp['nodes'])
8085

86+
def test_get_analysis_jobs_handler(self):
87+
user = User('test@foo.bar')
88+
dflt_analysis = user.default_analysis
89+
dflt_analysis.add_samples(
90+
{4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
91+
'1.SKM9.640192', '1.SKM4.640180']})
92+
new = Analysis.create(user, "newAnalysis", "A New Analysis",
93+
from_default=True)
94+
response = self.get('/analysis/description/%s/jobs/' % new.id)
95+
self.assertEqual(response.code, 200)
96+
97+
# There is only one job
98+
job_id = new.jobs[0].id
99+
obs = loads(response.body)
100+
exp = {job_id: {'status': 'queued', 'step': None, 'error': ""}}
101+
self.assertEqual(obs, exp)
102+
81103

82104
if __name__ == '__main__':
83105
main()

qiita_pet/templates/analysis_description.html

Lines changed: 89 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -77,37 +77,94 @@
7777
}
7878
};
7979

80-
/**
81-
* Draws the aritfact + job graph in the `analysis-network-div`
82-
*
83-
*/
84-
function populate_grap_div() {
85-
// Put the loading gif in the div
86-
show_loading('{% raw qiita_config.portal_dir %}', 'analysis-network-div');
87-
// Retrieve the information for the graph
88-
$.get("{% raw qiita_config.portal_dir %}/analysis/description/graph/", { analysis_id: {{analysis_id}}}, function(data) {
89-
var nodes = [];
90-
var edges = [];
91-
// Format edge list data
92-
for(var i = 0; i < data.edges.length; i++) {
93-
edges.push({from: data.edges[i][0], to: data.edges[i][1], arrows:'to'});
94-
}
95-
// Format node list data
96-
for(var i = 0; i < data.nodes.length; i++) {
97-
nodes.push({id: data.nodes[i][1], label: data.nodes[i][2], group: data.nodes[i][0]});
80+
$(document).ready(function(){
81+
// Create the new VUE component that is going to hold the artifact + job graph
82+
Vue.component('analysis-graph', {
83+
template: '<div class="col-md-12 graph" style="width:90%" id="analysis-network-div">',
84+
props: ['nodes', 'edges']
85+
});
86+
87+
new Vue({
88+
el: "#analysis-graph-vue",
89+
data: {
90+
nodes: [],
91+
edges: []
92+
},
93+
methods: {
94+
update_graph: function () {
95+
let vm = this;
96+
$.get("{% raw qiita_config.portal_dir %}/analysis/description/" + {{analysis_id}} + "/graph/", function(data) {
97+
// If there are no nodes in the graph, it means that we are waiting
98+
// for the jobs to generate the initial set of artifacts. Update
99+
// the job list
100+
if (data.nodes.length == 0) {
101+
vm.update_jobs();
102+
}
103+
else {
104+
// The initial set of artifacts has been created! Format the graph
105+
// data in a way that Vis.Network likes it
106+
// Format edge list data
107+
for(var i = 0; i < data.edges.length; i++) {
108+
vm.edges.push({from: data.edges[i][0], to: data.edges[i][1], arrows:'to'});
109+
}
110+
// Format node list data
111+
for(var i = 0; i < data.nodes.length; i++) {
112+
vm.nodes.push({id: data.nodes[i][1], label: data.nodes[i][2], group: data.nodes[i][0]});
113+
}
114+
draw_processing_graph(vm.nodes, vm.edges, 'analysis-network-div', populateContentArtifact, populateContentJob);
115+
// At this point we can show the graph and hide the job list
116+
$("#analysis-network-div").show();
117+
$("#analysis-job-div").hide();
118+
}
119+
})
120+
.fail(function(object, status, error_msg) {
121+
// Show an error message if something wrong happen, rather than
122+
// leaving the spinning wheel of death in there.
123+
$("#analysis-network-div").html("Error loading graph: " + status + " " + error_msg);
124+
$("#analysis-network-div").show();
125+
$("#analysis-job-div").hide();
126+
}
127+
);
128+
},
129+
update_jobs: function () {
130+
let vm = this;
131+
$.get("{% raw qiita_config.portal_dir %}/analysis/description/" + {{analysis_id}} + "/jobs/", function(data) {
132+
$("#analysis-job-div").html("");
133+
$("#analysis-job-div").append("<p>Hang tight, we are generating the initial set of files for your analysis: </p>");
134+
for(var jobid in data){
135+
var contents = "<b> Job: " + jobid + "</b> Status: " + data[jobid]['status'];
136+
// Only show step if error if they actually have a useful message
137+
if (data[jobid]['step']) {
138+
contents = contents + " Step: " + data[jobid]['step'] + "</br>";
139+
}
140+
if (data[jobid]['error']) {
141+
contents = contents + " Error: " + data[jobid]['error'] + "</br>";
142+
}
143+
$("#analysis-job-div").append(contents);
144+
}
145+
})
146+
.fail(function(object, status, error_msg) {
147+
$("#analysis-job-div").html("Error loading job information: " + status + " " + error_msg);
148+
}
149+
);
150+
}
151+
},
152+
mounted() {
153+
let vm = this;
154+
show_loading('{% raw qiita_config.portal_dir %}', 'analysis-network-div');
155+
$("#analysis-network-div").hide();
156+
// This call to udpate graph will take care of updating the jobs
157+
// if the graph is not available
158+
vm.update_graph();
159+
setInterval(function() {
160+
// Only update if the graph has not been generated yet
161+
if (vm.nodes.length == 0) {
162+
vm.update_graph();
163+
}
164+
}, 5000);
98165
}
99-
draw_processing_graph(nodes, edges, 'analysis-network-div', populateContentArtifact, populateContentJob);
100166
})
101-
.fail(function(object, status, error_msg) {
102-
$("#analysis-network-div").html("Error loading graph: " + status + " " + error_msg);
103-
}
104-
);
105-
}
106-
107-
$(document).ready(function(){
108-
populate_grap_div();
109167
});
110-
111168
</script>
112169
<style>
113170
.graph {
@@ -131,8 +188,11 @@ <h4><a class="btn btn-info" id="show-hide-network-btn" onclick="toggle_network_g
131188
<b>(Click nodes for more information, blue are jobs)</b>
132189
</div>
133190
</div>
191+
<div class='row' id="analysis-graph-vue">
192+
<analysis-graph></analysis-graph>
193+
</div>
134194
<div class='row'>
135-
<div class='col-md-12 graph' style='width:90%' id='analysis-network-div'>
195+
<div class='col-md-12' style='width:90%' id='analysis-job-div'>
136196
</div>
137197
</div>
138198
<div class='row'>

qiita_pet/templates/list_analyses.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ <h3><a href="{% raw qiita_config.portal_dir %}/study/list/">Create an analysis</
3232
{% set _id = analysis.id %}
3333
<tr>
3434
<td>
35-
<a href="{% raw qiita_config.portal_dir %}/analysis/description/{{analysis.id}}">{{analysis.name}}</a>
35+
<a href="{% raw qiita_config.portal_dir %}/analysis/description/{{analysis.id}}/">{{analysis.name}}</a>
3636
</td>
3737
<td>
3838
{{analysis.description}}

qiita_pet/webserver.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
UserMessagesHander, UserJobs)
2121
from qiita_pet.handlers.analysis_handlers import (
2222
ListAnalysesHandler, AnalysisSummaryAJAX, SelectedSamplesHandler,
23-
AnalysisDescriptionHandler, AnalysisGraphHandler, CreateAnalysisHandler)
23+
AnalysisDescriptionHandler, AnalysisGraphHandler, CreateAnalysisHandler,
24+
AnalysisJobsHandler)
2425
from qiita_pet.handlers.study_handlers import (
2526
StudyIndexHandler, StudyBaseInfoAJAX, SampleTemplateAJAX,
2627
StudyEditHandler, ListStudiesHandler, SearchStudiesAJAX, EBISubmitHandler,
@@ -96,7 +97,8 @@ def __init__(self):
9697
(r"/analysis/create/", CreateAnalysisHandler),
9798
(r"/analysis/selected/", SelectedSamplesHandler),
9899
(r"/analysis/selected/socket/", SelectedSocketHandler),
99-
(r"/analysis/description/graph/", AnalysisGraphHandler),
100+
(r"/analysis/description/(.*)/graph/", AnalysisGraphHandler),
101+
(r"/analysis/description/(.*)/jobs/", AnalysisJobsHandler),
100102
(r"/analysis/description/(.*)/", AnalysisDescriptionHandler),
101103
(r"/moi-ws/", MOIMessageHandler),
102104
(r"/consumer/", MessageHandler),

0 commit comments

Comments
 (0)