Merge lp:~ben-hutchings/ensoft-sextant/autocomplete-fix into lp:ensoft-sextant

Proposed by Ben Hutchings
Status: Superseded
Proposed branch: lp:~ben-hutchings/ensoft-sextant/autocomplete-fix
Merge into: lp:ensoft-sextant
Diff against target: 217 lines (+76/-30)
4 files modified
resources/sextant/web/interface.html (+6/-5)
resources/sextant/web/queryjavascript.js (+46/-15)
src/sextant/db_api.py (+10/-3)
src/sextant/web/server.py (+14/-7)
To merge this branch: bzr merge lp:~ben-hutchings/ensoft-sextant/autocomplete-fix
Reviewer Review Type Date Requested Status
Robert Pending
Review via email: mp+241401@code.launchpad.net

This proposal supersedes a proposal from 2014-11-05.

This proposal has been superseded by a proposal from 2014-11-11.

Description of the change

Web gui now has a hard limit on how many functions it is willing to get for the autocomplete menu. If there are more than this number of functions in the program, the empty list will be returned. Maximum number of functions is set to 75 at present - more than this leads to drop down lists not displaying properly sometimes.

Substring search in function names. Debouncing (one second timer at present).

To post a comment you must log in.
Revision history for this message
Ben Hutchings (ben-hutchings) wrote : Posted in a previous version of this proposal

Also the limit is hardcoded in web/server.py, not db_api.py.

34. By Ben Hutchings

removed debug output

35. By Ben Hutchings

fixed missing var in javascript, fixed unused global variables in python.

36. By Ben Hutchings

fixed bug by which timeout was never being tripped

37. By Ben Hutchings

whitespace changes, added missing var

38. By Ben Hutchings

indentation fix

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'resources/sextant/web/interface.html'
--- resources/sextant/web/interface.html 2014-09-04 09:46:18 +0000
+++ resources/sextant/web/interface.html 2014-11-11 16:13:40 +0000
@@ -17,8 +17,8 @@
17 <div class="toolbar">17 <div class="toolbar">
18 <div>18 <div>
19 Program: 19 Program:
20 <input list="program_names" id="program_name" class="textbox"20 <input list="program_names" id="program_name" class="textbox" style="width: 150px" />
21 onblur="get_names_for_autocomplete('funcs')" style="width: 150px" />21 <!-- onblur="get_names_for_autocomplete('funcs')" -->
22 <datalist id="program_names"></datalist>22 <datalist id="program_names"></datalist>
2323
24 <select id="query_list" class="dropdown" onchange="display_when();">24 <select id="query_list" class="dropdown" onchange="display_when();">
@@ -44,13 +44,14 @@
44 </div>44 </div>
45 <div id="toolbar-row2" style="margin-left: 234px;">45 <div id="toolbar-row2" style="margin-left: 234px;">
46 <!--list to populate arguments. Updates when program name is specified-->46 <!--list to populate arguments. Updates when program name is specified-->
47 <datalist id="function_names"></datalist>47 <datalist id="function_names_1"></datalist>
48 <datalist id="function_names_2"></datalist>
4849
49 <span id="argument_1" style="size:20;"></span>50 <span id="argument_1" style="size:20;"></span>
50 <input list="function_names" id="function_1" class="textbox" style="size:20;"></input>51 <input list="function_names_1" autocomplete="off" id="function_1" class="textbox" style="size:20;" onkeyup="get_names_for_autocomplete('funcs_with_timeout_1')"></input>
5152
52 <span id="argument_2" style="size:20;"></span>53 <span id="argument_2" style="size:20;"></span>
53 <input list="function_names" id="function_2" class="textbox" style="size:20;"></input>54 <input list="function_names_2" autocomplete="off" id="function_2" class="textbox" style="size:20;" onkeyup="get_names_for_autocomplete('funcs_with_timeout_2')"></input>
54 </div>55 </div>
55 </div>56 </div>
5657
5758
=== modified file 'resources/sextant/web/queryjavascript.js'
--- resources/sextant/web/queryjavascript.js 2014-09-29 21:08:33 +0000
+++ resources/sextant/web/queryjavascript.js 2014-11-11 16:13:40 +0000
@@ -6,42 +6,73 @@
6//server or function names from a specific program.6//server or function names from a specific program.
77
88
9function get_names_for_autocomplete(info_needed){9var timeout = null;
10
11
12function get_names_for_autocomplete(info_needed, search){
10 //Function queries to database to create a list 13 //Function queries to database to create a list
11 //which is used to populate the auto-complete text boxes.14 //which is used to populate the auto-complete text boxes.
15 if (typeof search == 'undefined') {
16 search = "";
17 }
18
12 var xmlhttp = new XMLHttpRequest();19 var xmlhttp = new XMLHttpRequest();
13 xmlhttp.onreadystatechange = function(){20 xmlhttp.onreadystatechange = function(){
14 if (xmlhttp.status = 200){21 if (xmlhttp.status = 200){
15 var values_list = xmlhttp.responseText;22 var values_list = xmlhttp.responseText;
23 do_timeout = false;
16 if (values_list != "") {24 if (values_list != "") {
17 values_list = JSON.parse(values_list);25 values_list = JSON.parse(values_list);
18 if (info_needed =='programs'){26 if (info_needed =='programs'){
19 //We need to populate the program names list27 //We need to populate the program names list
20 add_options("program_names", values_list);28 add_options("program_names", values_list);
21 }29 }
22 if (info_needed =='funcs'){30 if (info_needed == 'funcs_with_timeout_1') {
23 //We need to populate the functions list for the arguments31 add_options("function_names_1", values_list);
24 add_options("function_names", values_list);32 do_timeout = true;
25 } 33 }
34 if (info_needed == 'funcs_with_timeout_2') {
35 add_options("function_names_2", values_list);
36 do_timeout = true;
37 }
26 }38 }
27 }39 }
28 }40 }
29 if (info_needed == 'programs'){41 if (info_needed == 'programs'){
30 var string = "/database_properties?query=" + info_needed + "&program_name=";42 var string = "/database_properties?query=" + info_needed + "&program_name=";
43 xmlhttp.open("GET", string, true);
44 xmlhttp.send();
31 }45 }
32 else{46 else{
33 var string = "/database_properties?query=" + "functions" + 47 var target = null;
34 "&program_name=" + document.getElementById("program_name").value;48
35 if (info_needed == 'programs'){49 if (info_needed == 'funcs_with_timeout_1') {
36 var string = "/database_properties?query=" + 50 target = 'function_1';
37 info_needed + "&program_name=" + prog_name;51 }
38 }52 else {
53 target = 'function_2';
54 }
55
56 timeoutfn = function() {
57 var string = "/database_properties?query=" + "functions" +
58 "&program_name=" + document.getElementById("program_name").value +
59 "&search=" + document.getElementById(target).value;
60 xmlhttp.open("GET", string, true);
61 xmlhttp.send();
62 timeout = null;
63 };
64
65 if (do_timeout == true && timeout === null) {
66 timeout = window.setTimeout(timeoutfn, 1000);
67 } else if (do_timeout == true) {
68 window.clearTimeout(timeout);
69 timeout = window.setTimeout(timeoutfn, 1000);
70 } else {
71 timeoutfn();
72 }
73
39 //"GET" information from the specified url (string)74 //"GET" information from the specified url (string)
40 xmlhttp.open("GET", string, true);
41 xmlhttp.send();
42 }75 }
43 xmlhttp.open("GET", string, true);
44 xmlhttp.send();
45}76}
4677
4778
4879
=== modified file 'src/sextant/db_api.py'
--- src/sextant/db_api.py 2014-10-23 11:15:48 +0000
+++ src/sextant/db_api.py 2014-11-11 16:13:40 +0000
@@ -34,6 +34,8 @@
34# prior to copy over to the remote server.34# prior to copy over to the remote server.
35TMP_DIR = '/tmp/sextant'35TMP_DIR = '/tmp/sextant'
3636
37SEARCH_NAMES_LIMIT = 50
38
37# A function is deemed 'common' if it has more than this39# A function is deemed 'common' if it has more than this
38# many connections.40# many connections.
39COMMON_CUTOFF = 1041COMMON_CUTOFF = 10
@@ -832,7 +834,7 @@
832 result = self._db.query(q, returns=neo4jrestclient.Node)834 result = self._db.query(q, returns=neo4jrestclient.Node)
833 return bool(result)835 return bool(result)
834836
835 def get_function_names(self, program_name):837 def get_function_names(self, program_name, search, max_funcs):
836 """838 """
837 Execute query to retrieve a list of all functions in the program.839 Execute query to retrieve a list of all functions in the program.
838 Any of the output names can be used verbatim in any SextantConnection840 Any of the output names can be used verbatim in any SextantConnection
@@ -845,8 +847,13 @@
845 if not validate_query(program_name):847 if not validate_query(program_name):
846 return set()848 return set()
847849
848 q = (' MATCH (:program {{name: "{}"}})-[:subject]->(f:func)'850 if not search:
849 ' RETURN f.name').format(program_name)851 q = (' MATCH (:program {{name: "{}"}})-[:subject]->(f:func)'
852 ' RETURN f.name LIMIT {}').format(program_name, max_funcs)
853 else:
854 q = (' MATCH (:program {{name: "{}"}})-[:subject]->(f:func)'
855 ' WHERE f.name =~ ".*{}.*" RETURN f.name LIMIT {}'
856 .format(program_name, search, max_funcs))
850 return {func[0] for func in self._db.query(q)}857 return {func[0] for func in self._db.query(q)}
851858
852 def get_all_functions_called(self, program_name, function_calling):859 def get_all_functions_called(self, program_name, function_calling):
853860
=== modified file 'src/sextant/web/server.py'
--- src/sextant/web/server.py 2014-10-13 15:09:08 +0000
+++ src/sextant/web/server.py 2014-11-11 16:13:40 +0000
@@ -28,6 +28,7 @@
2828
29# global SextantConnection object which deals with the port forwarding29# global SextantConnection object which deals with the port forwarding
30CONNECTION = None30CONNECTION = None
31CONNECTION_MAX_FUNCTION_NAMES = 500
3132
32RESPONSE_CODE_OK = 20033RESPONSE_CODE_OK = 200
33RESPONSE_CODE_BAD_REQUEST = 40034RESPONSE_CODE_BAD_REQUEST = 400
@@ -218,8 +219,12 @@
218 return CONNECTION.get_program_names()219 return CONNECTION.get_program_names()
219220
220 @staticmethod221 @staticmethod
221 def _get_function_names(program_name):222 def _get_function_names(program_name, search=""):
222 return CONNECTION.get_function_names(program_name)223 max_funcs = 76;
224 programs = CONNECTION.programs_with_metadata()
225 result = CONNECTION.get_function_names(program_name, search, max_funcs)
226 return result if len(result) < max_funcs else set()
227
223228
224 @defer.inlineCallbacks229 @defer.inlineCallbacks
225 def _render_GET(self, request):230 def _render_GET(self, request):
@@ -247,19 +252,21 @@
247 request.finish()252 request.finish()
248 defer.returnValue(None)253 defer.returnValue(None)
249 program_name = request.args['program_name'][0]254 program_name = request.args['program_name'][0]
255 search = request.args.get('search', [''])[0]
250256
251 funcnames = yield deferToThread(self._get_function_names, program_name)257 funcnames = yield deferToThread(self._get_function_names, program_name, search)
252 if funcnames is None:258 if funcnames is None:
253 request.setResponseCode(404)259 request.setResponseCode(404)
254 request.setHeader("content-type", "text/plain")260 request.setHeader("content-type", "text/plain")
255 request.write("No program with name %s was found in the Sextant." % escape(program_name))261 request.write("No program with name %s was found in the Sextant." % escape(program_name))
256 request.finish()262 request.finish()
257 defer.returnValue(None)263 defer.returnValue(None)
264 else:
265 request.setHeader("content-type", "application/json")
266 request.write(json.dumps(list(funcnames)))
258267
259 request.setHeader("content-type", "application/json")268 request.finish()
260 request.write(json.dumps(list(funcnames)))269 defer.returnValue(None)
261 request.finish()
262 defer.returnValue(None)
263270
264 else:271 else:
265 request.setResponseCode(400)272 request.setResponseCode(400)

Subscribers

People subscribed via source and target branches