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: 219 lines (+78/-30)
4 files modified
resources/sextant/web/interface.html (+6/-5)
resources/sextant/web/queryjavascript.js (+48/-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+240748@code.launchpad.net

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

Commit message

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.

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.

To post a comment you must log in.
32. By Ben Hutchings

actually use the empty set rather than the set containing a black string.

Revision history for this message
Ben Hutchings (ben-hutchings) wrote :

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

33. By Ben Hutchings

autocomplete now wildcard matches function names in the database - only displaying lists if there are 75 or fewer results.

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
1=== modified file 'resources/sextant/web/interface.html'
2--- resources/sextant/web/interface.html 2014-09-04 09:46:18 +0000
3+++ resources/sextant/web/interface.html 2014-11-11 12:12:05 +0000
4@@ -17,8 +17,8 @@
5 <div class="toolbar">
6 <div>
7 Program:
8- <input list="program_names" id="program_name" class="textbox"
9- onblur="get_names_for_autocomplete('funcs')" style="width: 150px" />
10+ <input list="program_names" id="program_name" class="textbox" style="width: 150px" />
11+ <!-- onblur="get_names_for_autocomplete('funcs')" -->
12 <datalist id="program_names"></datalist>
13
14 <select id="query_list" class="dropdown" onchange="display_when();">
15@@ -44,13 +44,14 @@
16 </div>
17 <div id="toolbar-row2" style="margin-left: 234px;">
18 <!--list to populate arguments. Updates when program name is specified-->
19- <datalist id="function_names"></datalist>
20+ <datalist id="function_names_1"></datalist>
21+ <datalist id="function_names_2"></datalist>
22
23 <span id="argument_1" style="size:20;"></span>
24- <input list="function_names" id="function_1" class="textbox" style="size:20;"></input>
25+ <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>
26
27 <span id="argument_2" style="size:20;"></span>
28- <input list="function_names" id="function_2" class="textbox" style="size:20;"></input>
29+ <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>
30 </div>
31 </div>
32
33
34=== modified file 'resources/sextant/web/queryjavascript.js'
35--- resources/sextant/web/queryjavascript.js 2014-09-29 21:08:33 +0000
36+++ resources/sextant/web/queryjavascript.js 2014-11-11 12:12:05 +0000
37@@ -6,42 +6,75 @@
38 //server or function names from a specific program.
39
40
41-function get_names_for_autocomplete(info_needed){
42+var timeout = null;
43+
44+
45+function get_names_for_autocomplete(info_needed, search){
46 //Function queries to database to create a list
47 //which is used to populate the auto-complete text boxes.
48+ if (typeof search == 'undefined') {
49+ search = "";
50+ }
51+
52 var xmlhttp = new XMLHttpRequest();
53 xmlhttp.onreadystatechange = function(){
54 if (xmlhttp.status = 200){
55 var values_list = xmlhttp.responseText;
56+ do_timeout = false;
57 if (values_list != "") {
58+ document.getElementById('function_names_output').innerHTML = xmlhttp.responseText;
59+ show_item("function_names_output");
60 values_list = JSON.parse(values_list);
61 if (info_needed =='programs'){
62 //We need to populate the program names list
63 add_options("program_names", values_list);
64 }
65- if (info_needed =='funcs'){
66- //We need to populate the functions list for the arguments
67- add_options("function_names", values_list);
68- }
69+ if (info_needed == 'funcs_with_timeout_1') {
70+ add_options("function_names_1", values_list);
71+ do_timeout = true;
72+ }
73+ if (info_needed == 'funcs_with_timeout_2') {
74+ add_options("function_names_2", values_list);
75+ do_timeout = true;
76+ }
77 }
78 }
79 }
80 if (info_needed == 'programs'){
81 var string = "/database_properties?query=" + info_needed + "&program_name=";
82+ xmlhttp.open("GET", string, true);
83+ xmlhttp.send();
84 }
85 else{
86- var string = "/database_properties?query=" + "functions" +
87- "&program_name=" + document.getElementById("program_name").value;
88- if (info_needed == 'programs'){
89- var string = "/database_properties?query=" +
90- info_needed + "&program_name=" + prog_name;
91- }
92+ var target = null;
93+
94+ if (info_needed == 'funcs_with_timeout_1') {
95+ target = 'function_1';
96+ }
97+ else {
98+ target = 'function_2';
99+ }
100+
101+ timeoutfn = function() {
102+ var string = "/database_properties?query=" + "functions" +
103+ "&program_name=" + document.getElementById("program_name").value +
104+ "&search=" + document.getElementById(target).value;
105+ xmlhttp.open("GET", string, true);
106+ xmlhttp.send();
107+ timeout = null;
108+ };
109+
110+ if (do_timeout == true && timeout === null) {
111+ timeout = window.setTimeout(timeoutfn, 1000);
112+ } else if (do_timeout == true) {
113+ window.clearTimeout(timeout);
114+ timeout = window.setTimeout(timeoutfn, 1000);
115+ } else {
116+ timeoutfn();
117+ }
118+
119 //"GET" information from the specified url (string)
120- xmlhttp.open("GET", string, true);
121- xmlhttp.send();
122 }
123- xmlhttp.open("GET", string, true);
124- xmlhttp.send();
125 }
126
127
128
129=== modified file 'src/sextant/db_api.py'
130--- src/sextant/db_api.py 2014-10-23 11:15:48 +0000
131+++ src/sextant/db_api.py 2014-11-11 12:12:05 +0000
132@@ -34,6 +34,8 @@
133 # prior to copy over to the remote server.
134 TMP_DIR = '/tmp/sextant'
135
136+SEARCH_NAMES_LIMIT = 50
137+
138 # A function is deemed 'common' if it has more than this
139 # many connections.
140 COMMON_CUTOFF = 10
141@@ -832,7 +834,7 @@
142 result = self._db.query(q, returns=neo4jrestclient.Node)
143 return bool(result)
144
145- def get_function_names(self, program_name):
146+ def get_function_names(self, program_name, search, max_funcs):
147 """
148 Execute query to retrieve a list of all functions in the program.
149 Any of the output names can be used verbatim in any SextantConnection
150@@ -845,8 +847,13 @@
151 if not validate_query(program_name):
152 return set()
153
154- q = (' MATCH (:program {{name: "{}"}})-[:subject]->(f:func)'
155- ' RETURN f.name').format(program_name)
156+ if not search:
157+ q = (' MATCH (:program {{name: "{}"}})-[:subject]->(f:func)'
158+ ' RETURN f.name LIMIT {}').format(program_name, max_funcs)
159+ else:
160+ q = (' MATCH (:program {{name: "{}"}})-[:subject]->(f:func)'
161+ ' WHERE f.name =~ ".*{}.*" RETURN f.name LIMIT {}'
162+ .format(program_name, search, max_funcs))
163 return {func[0] for func in self._db.query(q)}
164
165 def get_all_functions_called(self, program_name, function_calling):
166
167=== modified file 'src/sextant/web/server.py'
168--- src/sextant/web/server.py 2014-10-13 15:09:08 +0000
169+++ src/sextant/web/server.py 2014-11-11 12:12:05 +0000
170@@ -28,6 +28,7 @@
171
172 # global SextantConnection object which deals with the port forwarding
173 CONNECTION = None
174+CONNECTION_MAX_FUNCTION_NAMES = 500
175
176 RESPONSE_CODE_OK = 200
177 RESPONSE_CODE_BAD_REQUEST = 400
178@@ -218,8 +219,12 @@
179 return CONNECTION.get_program_names()
180
181 @staticmethod
182- def _get_function_names(program_name):
183- return CONNECTION.get_function_names(program_name)
184+ def _get_function_names(program_name, search=""):
185+ max_funcs = 76;
186+ programs = CONNECTION.programs_with_metadata()
187+ result = CONNECTION.get_function_names(program_name, search, max_funcs)
188+ return result if len(result) < max_funcs else set()
189+
190
191 @defer.inlineCallbacks
192 def _render_GET(self, request):
193@@ -247,19 +252,21 @@
194 request.finish()
195 defer.returnValue(None)
196 program_name = request.args['program_name'][0]
197+ search = request.args.get('search', [''])[0]
198
199- funcnames = yield deferToThread(self._get_function_names, program_name)
200+ funcnames = yield deferToThread(self._get_function_names, program_name, search)
201 if funcnames is None:
202 request.setResponseCode(404)
203 request.setHeader("content-type", "text/plain")
204 request.write("No program with name %s was found in the Sextant." % escape(program_name))
205 request.finish()
206 defer.returnValue(None)
207+ else:
208+ request.setHeader("content-type", "application/json")
209+ request.write(json.dumps(list(funcnames)))
210
211- request.setHeader("content-type", "application/json")
212- request.write(json.dumps(list(funcnames)))
213- request.finish()
214- defer.returnValue(None)
215+ request.finish()
216+ defer.returnValue(None)
217
218 else:
219 request.setResponseCode(400)

Subscribers

People subscribed via source and target branches