Merge lp:~isaacd-u/ensoft-sextant/program-selection into lp:ensoft-sextant

Proposed by Isaac Dunn
Status: Merged
Approved by: ChrisD
Approved revision: 68
Merged at revision: 47
Proposed branch: lp:~isaacd-u/ensoft-sextant/program-selection
Merge into: lp:ensoft-sextant
Diff against target: 489 lines (+178/-52)
5 files modified
resources/sextant/web/index.html (+14/-11)
resources/sextant/web/interface.html (+14/-14)
resources/sextant/web/queryjavascript.js (+53/-16)
resources/sextant/web/style_sheet.css (+57/-7)
src/sextant/web/server.py (+40/-4)
To merge this branch: bzr merge lp:~isaacd-u/ensoft-sextant/program-selection
Reviewer Review Type Date Requested Status
ChrisD Approve
Review via email: mp+264265@code.launchpad.net

Commit message

Merging changes to interface (improved program selection).
Selection of the program to explore now happens on the front page, and a program can now be explored by accessing its specific URL (/program/{program name}), without going via the front page.

Description of the change

Changes to the user interface: program selection now happens on the front page, and a program can now be explored by accessing its specific URL (/program/{program name}).

To post a comment you must log in.
Revision history for this message
ChrisD (gingerchris) wrote :

Looks good!
Added some inline comments for some bits that would be good to clean up.

66. By Isaac Dunn <email address hidden>

Cache list of program names to prevent synchronously dealing with URL validation requests.
The list is initialised when the server is started, and is updated every time
the list of programs is requested (e.g. if index.html is accessed).

67. By Isaac Dunn <email address hidden>

Improved button colours (especially on hover).

68. By Isaac Dunn <email address hidden>

Merged Kath's changes.

Commits merged:
  Kath N 2015-07-09 Small changes to syntax of queryjavascript file, adding "use:strict" statement
  Kath N 2015-07-09 Tidied up queryjavascript.js, removed references to queries of type 'programs', since this is no longer used.

Revision history for this message
ChrisD (gingerchris) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'resources/sextant/web/index.html'
--- resources/sextant/web/index.html 2014-09-04 09:46:18 +0000
+++ resources/sextant/web/index.html 2015-07-09 15:37:33 +0000
@@ -12,20 +12,23 @@
12 <link rel="stylesheet" type="text/css" href="style_sheet.css"/>12 <link rel="stylesheet" type="text/css" href="style_sheet.css"/>
13 <title>Sextant</title>13 <title>Sextant</title>
14</head>14</head>
15<body style="height:100%" class="titlescreen">15<body style="height:100%" class="titlescreen" onload="get_names_for_autocomplete('programs_with_metadata')">
16 <div class="centered">16 <div id="wholebody">
17 <div id="titlescreen-logo-text">17 <div class="titlescreen-topbar">
18 Sextant18 <div id="titlescreen-logo-text">Sextant</div>
19 </div>19 <p style="text-align:center"> Choose a program to explore: </p>
20 <div>20 </div>
21 <button class="button" onclick="window.location='interface.html'">Open Sextant Explorer</button>21
22 <!--<button class="button">View Programs</button>-->22 <div id="main" class="main">
23 </div>23 <div id="programs_list" type="scrolling-block"> </div>
24 </div>24 </div>
2525
26 <div id="titlescreen-bottombar">26 <div id="titlescreen-bottombar" type="titlescreen-bottombar">
27 To add a program to Sextant, use '<b>sextant add-program</b>' from the command line27 To add a program to Sextant, use '<b>sextant add-program</b>' from the command line
28 </div>
29
28 </div>30 </div>
31 <script src="queryjavascript.js"></script>
2932
30</body>33</body>
31</html>34</html>
3235
=== modified file 'resources/sextant/web/interface.html'
--- resources/sextant/web/interface.html 2014-11-24 11:21:16 +0000
+++ resources/sextant/web/interface.html 2015-07-09 15:37:33 +0000
@@ -9,18 +9,16 @@
9<html>9<html>
10<head>10<head>
11<meta charset="utf-8"/>11<meta charset="utf-8"/>
12 <link rel="stylesheet" type="text/css" href="style_sheet.css"/>12 <link rel="stylesheet" type="text/css" href="/style_sheet.css"/>
13 <title> Sextant Explorer </title>13 <title> Sextant Explorer </title>
14 <script src="/queryjavascript.js"></script>
14</head>15</head>
1516
16<body onload="get_names_for_autocomplete('programs'); set_arguments('', ''); show_item('welcome')">17<body onload="get_names_for_autocomplete('funcs_both'); set_arguments('', ''); show_item('welcome')">
17 <div class="toolbar">18 <div class="toolbar">
18 <div>19 <div>
19 Program: 20 <button class="button" onclick="window.location.href='/'">Choose new program</button>
20 <input list="program_names" id="program_name" class="textbox" style="width: 150px"21
21 onchange="get_names_for_autocomplete('funcs_both')"/>
22 <datalist id="program_names"></datalist>
23
24 <select id="query_list" class="dropdown" onchange="display_when();">22 <select id="query_list" class="dropdown" onchange="display_when();">
25 <option value="whole_program">Whole graph</option>23 <option value="whole_program">Whole graph</option>
26 <option value="functions_calling">24 <option value="functions_calling">
@@ -36,20 +34,20 @@
36 </select>34 </select>
37 &nbsp;&nbsp;&nbsp;35 &nbsp;&nbsp;&nbsp;
38 <label>36 <label>
37 Suppress common functions?
39 <input type="checkbox" id="suppress_common" value="True"></input>38 <input type="checkbox" id="suppress_common" value="True"></input>
40 Suppress common functions?
41 </label>39 </label>
42 <label>40 <label>
41 Limit to internal calls?
43 <input type="checkbox" id="limit_internal" value="True"></input>42 <input type="checkbox" id="limit_internal" value="True"></input>
44 Limit to internal calls?
45 </label>43 </label>
46 <label>44 <label>
45 Maximum call depth:
47 <input type="number" id="max_depth" value="1" min="0" max="10"></input>46 <input type="number" id="max_depth" value="1" min="0" max="10"></input>
48 Maximum call depth.
49 </label>47 </label>
50 <button class="button" style="float:right; margin: 1px 20px -1px 0;" onclick="execute_query()">Run Query</button>48 <button class="button" style="float:right; margin: 1px 20px -1px 0;" onclick="execute_query()">Run Query</button>
51 </div>49 </div>
52 <div id="toolbar-row2" style="margin-left: 234px;">50 <div id="toolbar-row2">
53 <!--list to populate arguments. Updates when program name is specified-->51 <!--list to populate arguments. Updates when program name is specified-->
54 <datalist id="function_names_1"></datalist>52 <datalist id="function_names_1"></datalist>
55 <datalist id="function_names_2"></datalist>53 <datalist id="function_names_2"></datalist>
@@ -65,7 +63,7 @@
6563
6664
67 <!-- Output for image file-->65 <!-- Output for image file-->
68 <img id=output_image src="sextant.jpg"66 <img id=output_image src="/sextant.gif"
69 class="pos_img"67 class="pos_img"
70 style="align: bottom; font-style: italic; color: #C0C0C0; font-size: 15px" />68 style="align: bottom; font-style: italic; color: #C0C0C0; font-size: 15px" />
7169
@@ -74,7 +72,10 @@
7472
75 <div class="centered" id="welcome">73 <div class="centered" id="welcome">
76 <div class="title">Welcome to Sextant Explorer</div>74 <div class="title">Welcome to Sextant Explorer</div>
77 <div class="subtitle"><b>To begin</b>: enter a program name, choose a query, and click 'Run Query'</div>75 <div class="subtitle">
76 Your current program is <b id="prog_name"></b><br>
77 <b>To begin</b>: choose a query, and click 'Run Query'</div>
78 <script>document.getElementById("prog_name").innerHTML = get_program_name()</script>
78 </div>79 </div>
79 </div>80 </div>
8081
@@ -90,6 +91,5 @@
90 </div>91 </div>
91 </div>92 </div>
9293
93 <script src="queryjavascript.js"></script>
94</body>94</body>
95</html>95</html>
9696
=== modified file 'resources/sextant/web/queryjavascript.js'
--- resources/sextant/web/queryjavascript.js 2014-12-02 14:00:57 +0000
+++ resources/sextant/web/queryjavascript.js 2015-07-09 15:37:33 +0000
@@ -5,27 +5,26 @@
5//Runs query and "GET"s either program names uploaded on the 5//Runs query and "GET"s either program names uploaded on the
6//server or function names from a specific program.6//server or function names from a specific program.
77
88"use strict";
9var timeout = null;9var timeout = null;
10var do_timeout = false;10var do_timeout = false;
1111
12
13function get_names_for_autocomplete(info_needed, search) {12function get_names_for_autocomplete(info_needed, search) {
14 //Function queries to database to create a list 13 //Function queries to database to create a list
15 //which is used to populate the auto-complete text boxes.14 //which is used to populate the auto-complete text boxes,
15 //and to add program buttons on index.html
16 if (typeof search == 'undefined') {16 if (typeof search == 'undefined') {
17 search = "";17 search = "";
18 }18 }
19 19
20 var xmlhttp = new XMLHttpRequest();20 var xmlhttp = new XMLHttpRequest();
21 xmlhttp.onreadystatechange = function() {21 xmlhttp.onreadystatechange = function() {
22 if (xmlhttp.status = 200) {22 if (xmlhttp.status == 200) {
23 var values_list = xmlhttp.responseText;23 var values_list = xmlhttp.responseText;
24 if (values_list != "") {24 if (values_list != "") {
25 values_list = JSON.parse(values_list);25 values_list = JSON.parse(values_list);
26 if (info_needed =='programs') {26 if (info_needed =='programs_with_metadata') {
27 //We need to populate the program names list27 add_program_buttons_with_metadata(values_list);
28 add_options("program_names", values_list);
29 do_timeout = false;28 do_timeout = false;
30 }29 }
31 if (info_needed == 'funcs_with_timeout_1') {30 if (info_needed == 'funcs_with_timeout_1') {
@@ -41,12 +40,11 @@
41 add_options("function_names_2", values_list);40 add_options("function_names_2", values_list);
42 do_timeout = false;41 do_timeout = false;
43 }42 }
44
45 }43 }
46 }44 }
47 }45 }
48 46
49 if (info_needed == 'programs') {47 if (info_needed == 'programs_with_metadata') {
50 var string = "/database_properties?query=" + info_needed + "&program_name=";48 var string = "/database_properties?query=" + info_needed + "&program_name=";
51 xmlhttp.open("GET", string, true);49 xmlhttp.open("GET", string, true);
52 xmlhttp.send();50 xmlhttp.send();
@@ -61,7 +59,7 @@
6159
62 var timeoutfn = function() {60 var timeoutfn = function() {
63 var string = "/database_properties?query=" + "functions" + 61 var string = "/database_properties?query=" + "functions" +
64 "&program_name=" + document.getElementById("program_name").value +62 "&program_name=" + get_program_name() +
65 "&search=" + document.getElementById(target).value;63 "&search=" + document.getElementById(target).value;
66 xmlhttp.open("GET", string, true);64 xmlhttp.open("GET", string, true);
67 xmlhttp.send();65 xmlhttp.send();
@@ -85,7 +83,7 @@
85function add_options(selectedlist, values_list) {83function add_options(selectedlist, values_list) {
86 //Adds all the options obtained from the list of program 84 //Adds all the options obtained from the list of program
87 //names or function names to an auto complete drop-down box85 //names or function names to an auto complete drop-down box
88 var options = ''86 var options = '';
89 if (values_list.length == 1 || values_list.length ==0) {87 if (values_list.length == 1 || values_list.length ==0) {
90 options += '<option value="'+values_list+'"/>';88 options += '<option value="'+values_list+'"/>';
91 } else {89 } else {
@@ -96,6 +94,35 @@
96 document.getElementById(selectedlist).innerHTML = options;94 document.getElementById(selectedlist).innerHTML = options;
97}95}
9896
97function add_program_buttons_with_metadata(values_list) {
98 // Adds one button for each available program to the button list (in index.html)
99 // Also adds the required metadata, currently:
100 // {program_name} (in bold)
101 // User: {uploader}
102 // Date: {date}
103
104 // sorts the programs so that most recently uploaded appear first
105 var field = "date";
106 values_list.sort(function(x,y) {
107 if (x[field] > y[field]) {
108 return -1;
109 }
110 if (x[field] < y[field]) {
111 return 1;
112 }
113 return 0;
114 });
115
116 var buttons = '';
117 for (var i=0; i < values_list.length;++i) {
118 // Add button with id = program name and onclick = go to /program/{program name} and text as required
119 var date = values_list[i]["date"].split(' ')[0];
120 buttons += '<button type="button" class="program_button" id=' + values_list[i]["program_name"] +
121 ' onclick=window.location="/program/' + values_list[i]["program_name"] + '">' + '<b>' + values_list[i]["program_name"] + '</b> <br> <small>User: </small>' + values_list[i]["uploader"] + '<br> <small>Date: </small>' + date + '</button>';
122 }
123 document.getElementById("programs_list").innerHTML = buttons;
124}
125
99126
100function set_argument(number, label) {127function set_argument(number, label) {
101 var argEl = document.getElementById("argument_" + number);128 var argEl = document.getElementById("argument_" + number);
@@ -126,7 +153,7 @@
126 var query_list = document.getElementById("query_list");153 var query_list = document.getElementById("query_list");
127154
128 var no_functions = new Array();155 var no_functions = new Array();
129 var prog_name = document.getElementById("program_name").value;156 var prog_name = get_program_name();
130 if (query_list.options[query_list.selectedIndex].value == "functions_calling") {157 if (query_list.options[query_list.selectedIndex].value == "functions_calling") {
131 set_arguments("Function being called", "");158 set_arguments("Function being called", "");
132 }159 }
@@ -151,7 +178,7 @@
151178
152function execute_query() {179function execute_query() {
153 document.getElementById("output_image").src = "";180 document.getElementById("output_image").src = "";
154181
155 //Returns error in alert window if query not executed properly, 182 //Returns error in alert window if query not executed properly,
156 //otherwise performs the query and outputs it183 //otherwise performs the query and outputs it
157 show_item("please-wait");184 show_item("please-wait");
@@ -159,14 +186,14 @@
159 if (query_id == "function_names") {186 if (query_id == "function_names") {
160 //url for page containing all function names187 //url for page containing all function names
161 var string = "/database_properties?program_name=" + 188 var string = "/database_properties?program_name=" +
162 document.getElementById("program_name").value + "&query=functions";189 get_program_name() + "&query=functions";
163 } else {190 } else {
164 //If not function names we will want a graph as an output; 191 //If not function names we will want a graph as an output;
165 //url returns svg file of graph.192 //url returns svg file of graph.
166 // We use a random number argument to prevent caching.193 // We use a random number argument to prevent caching.
167 var string = "/output_graph.svg?stop_cache=" + String(Math.random()) + "&program_name=" + 194 var string = "/output_graph.svg?stop_cache=" + String(Math.random()) + "&program_name=" +
168 document.getElementById("program_name").value + 195 get_program_name() +
169 "&query=" + query_id + "&function_calling=";196 "&query=" + query_id + "&function_calling=";
170 string = string + document.getElementById("function_1").value + 197 string = string + document.getElementById("function_1").value +
171 "&function_called=" + document.getElementById("function_2").value;198 "&function_called=" + document.getElementById("function_2").value;
172 string = string + "&suppress_common=" + 199 string = string + "&suppress_common=" +
@@ -232,3 +259,13 @@
232 show_item("error");259 show_item("error");
233 document.getElementById("error-msg").innerHTML = msg;260 document.getElementById("error-msg").innerHTML = msg;
234}261}
262
263function get_program_name() {
264 // Provided there is a program name in the url (expected form is localhost:#/program/prog_name
265 // this returns the prog_name
266
267 var url = document.URL;
268 var prog_name = url.split('/').reverse()[0];
269 return prog_name;
270}
271
235272
=== modified file 'resources/sextant/web/style_sheet.css'
--- resources/sextant/web/style_sheet.css 2014-09-04 09:46:18 +0000
+++ resources/sextant/web/style_sheet.css 2015-07-09 15:37:33 +0000
@@ -15,8 +15,9 @@
15 padding: 0;15 padding: 0;
16}16}
1717
18
18body.titlescreen {19body.titlescreen {
19 background-color: rgb(105, 145, 172);20 background: rgb(105, 145, 172);
20 color: rgb(245, 245, 245);21 color: rgb(245, 245, 245);
21}22}
2223
@@ -40,37 +41,56 @@
40 text-align:center; background:#00000041 text-align:center; background:#000000
41}42}
4243
4344div.main {
4445 height:auto;
4546 padding:5px;
47 padding-top:10px;
48 margin-bottom:60px;
49 width:60%;
50 margin-left:20%;
51 text-align:center;
52}
4653
47div.centered {54div.centered {
48 position: absolute;55 position: absolute;
49 left: 50%;56 left: 50%;
50 top: 40%; /* for good design we position nearer the top */57 top: 40%; /* for good design we position nearer the top */
51 transform: translate(-50%, -40%); 58 transform: translate(-50%, -40%);
52 -webkit-transform: translate(-50%, -40%);59 -webkit-transform: translate(-50%, -40%);
53 -moz-transform: translate(-50%, -40%);60 -moz-transform: translate(-50%, -40%);
54 -ms-transform: translate(-50%, -40%);61 -ms-transform: translate(-50%, -40%);
55 text-align: center;62 text-align: center;
56}63}
5764
65scrolling-block {
66 height:auto;
67 overflow-y:auto;
68}
69
58#titlescreen-logo-text {70#titlescreen-logo-text {
59 font-size: 80px;71 font-size: 80px;
60 font-family: 'Poiret One', sans-serif;72 font-family: 'Poiret One', sans-serif;
61 letter-spacing: -2px;73 letter-spacing: -2px;
62 padding-bottom: 4px;74 padding-bottom: 4px;
75 text-align:center;
63}76}
6477
65#titlescreen-bottombar {78#titlescreen-bottombar {
66 font-size: 20px;79 font-size: 20px;
67 position: absolute;80 position: fixed;
68 left: 0;81 left: 0;
69 bottom: 0;82 bottom: 0;
70 right: 0;83 right: 0;
71 height: 80px;84 height: 40px;
72 font-weight: 300;85 font-weight: 300;
73 text-align: center;86 text-align: center;
87 background:rgb(105,145,172);
88}
89
90#titlescreen-topbar {
91 position:fixed;
92 height:60px;
93 background:rgb(105,145,172);
74}94}
7595
76.toolbar {96.toolbar {
@@ -90,6 +110,36 @@
90 border: none;110 border: none;
91}111}
92112
113.program_button {
114 background: rgb(135, 175, 202);
115 background: -moz-linear-gradient(top,rgb(135, 175, 202) 0%,rgb(95, 135, 162) 100%);
116 background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,rgb(135, 175, 202)),color-stop(100%,rgb(95, 135, 162)));
117 background: -webkit-linear-gradient(top,rgb(135, 175, 202) 0%,rgb(95, 135, 162) 100%);
118 background: -o-linear-gradient(top,rgb(135, 175, 202) 0%,rgb(95, 135, 162) 100%);
119 background: -ms-linear-gradient(top,rgb(135, 175, 202) 0%,rgb(95, 135, 162) 100%);
120 background: linear-gradient(top,rgb(135, 175, 202) 0%,rgb(95, 135, 162) 100%);
121 filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='rgb(135, 175, 202)',endColorstr='rgb(95, 135, 162)',GradientType=0);
122 padding:8px 13px;
123 color:#fff;
124 font-family:'Source Sans Pro',sans-serif;
125 font-size:17px;
126 border-radius:4px;
127 -moz-border-radius:4px;
128 -webkit-border-radius:4px;
129 border:1px solid rgb(95, 135, 162)
130}
131
132.program_button:hover{
133 background: rgb(125, 165, 192);
134 background: -moz-linear-gradient(top,rgb(155, 195, 222) 0%,rgb(125, 165, 192) 100%);
135 background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,rgb(155, 195, 222)),color-stop(100%,rgb(125, 165, 192)));
136 background: -webkit-linear-gradient(top,rgb(155, 195, 222) 0%,rgb(125, 165, 192) 100%);
137 background: -o-linear-gradient(top,rgb(155, 195, 222) 0%,rgb(125, 165, 192) 100%);
138 background: -ms-linear-gradient(top,rgb(155, 195, 222) 0%,rgb(125, 165, 192) 100%);
139 background: linear-gradient(top,rgb(155, 195, 222) 0%,rgb(125, 165, 192) 100%);
140 filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='rgb(155, 195, 222)',endColorstr='rgb(125, 165, 192)',GradientType=0);
141}
142
93.textbox {143.textbox {
94 background-color: rgb(245, 245, 245);144 background-color: rgb(245, 245, 245);
95 border: 1px solid rgb(103, 114, 122);145 border: 1px solid rgb(103, 114, 122);
96146
=== modified file 'src/sextant/web/server.py'
--- src/sextant/web/server.py 2014-12-18 17:00:51 +0000
+++ src/sextant/web/server.py 2015-07-09 15:37:33 +0000
@@ -7,7 +7,7 @@
7# Note: this must be run in Python 2.7# Note: this must be run in Python 2.
88
9from twisted.web.server import Site, NOT_DONE_YET9from twisted.web.server import Site, NOT_DONE_YET
10from twisted.web.resource import Resource10from twisted.web.resource import Resource, NoResource
11from twisted.web.static import File11from twisted.web.static import File
12from twisted.internet import reactor12from twisted.internet import reactor
13from twisted.internet.threads import deferToThread13from twisted.internet.threads import deferToThread
@@ -33,6 +33,10 @@
33# global SextantConnection object which deals with the port forwarding33# global SextantConnection object which deals with the port forwarding
34CONNECTION = None34CONNECTION = None
3535
36# global list of program names for validation - prevents synchronously fetching
37# on page loads, occupying the server
38PROGRAM_NAMES = []
39
36# The maximum number of matches to display for autocomplete. If more than40# The maximum number of matches to display for autocomplete. If more than
37# this are matched, nothing will be returned.41# this are matched, nothing will be returned.
38AUTOCOMPLETE_NAMES_LIMIT = 7542AUTOCOMPLETE_NAMES_LIMIT = 75
@@ -250,7 +254,19 @@
250254
251 @staticmethod255 @staticmethod
252 def _get_program_names():256 def _get_program_names():
253 return CONNECTION.get_program_names()257 # Keep list used for URL validation up to date
258 global PROGRAM_NAMES
259 PROGRAM_NAMES = CONNECTION.get_program_names()
260 return PROGRAM_NAMES
261
262 @staticmethod
263 def _get_programs_with_metadata():
264 # Converts set of namedtuples to a list of dictionaries
265 # for serialisation into JSON.
266 global PROGRAM_NAMES
267 progs_with_metadata = CONNECTION.programs_with_metadata()
268 PROGRAM_NAMES = [ntuple.program_name for ntuple in progs_with_metadata]
269 return [ntuple._asdict() for ntuple in progs_with_metadata]
254270
255 @staticmethod271 @staticmethod
256 def _get_function_names(program_name, search=""):272 def _get_function_names(program_name, search=""):
@@ -283,6 +299,13 @@
283 request.finish()299 request.finish()
284 defer.returnValue(None)300 defer.returnValue(None)
285301
302 elif query == 'programs_with_metadata':
303 request.setHeader("content-type", "application/json")
304 prog_metadata = yield deferToThread(self._get_programs_with_metadata)
305 request.write(json.dumps(prog_metadata))
306 request.finish()
307 defer.returnValue(None)
308
286 elif query == 'functions':309 elif query == 'functions':
287 if "program_name" not in request.args:310 if "program_name" not in request.args:
288 request.setResponseCode(400)311 request.setResponseCode(400)
@@ -310,7 +333,7 @@
310 else:333 else:
311 request.setResponseCode(400)334 request.setResponseCode(400)
312 request.setHeader("content-type", "text/plain")335 request.setHeader("content-type", "text/plain")
313 request.write("'Query' parameter should be 'programs' or 'functions'.")336 request.write("'Query' parameter should be 'programs', 'programs_with_metadata' or 'functions'.")
314 request.finish()337 request.finish()
315 defer.returnValue(None)338 defer.returnValue(None)
316339
@@ -320,10 +343,12 @@
320343
321344
322def serve_site(connection, port):345def serve_site(connection, port):
323 global CONNECTION346 global CONNECTION, PROGRAM_NAMES
324347
325 CONNECTION = connection348 CONNECTION = connection
326349
350 # saves making this synchronous call every page load
351 PROGRAM_NAMES = CONNECTION.get_program_names()
327352
328 # serve static directory at root353 # serve static directory at root
329 root = File(os.path.join(environment.RESOURCES_DIR, 'sextant', 'web'))354 root = File(os.path.join(environment.RESOURCES_DIR, 'sextant', 'web'))
@@ -331,6 +356,17 @@
331 # serve a dynamic Echoer webpage at /echoer.html356 # serve a dynamic Echoer webpage at /echoer.html
332 root.putChild("echoer.html", Echoer())357 root.putChild("echoer.html", Echoer())
333358
359 # serve static files at /program/{anything}
360 grandchild = File(os.path.join(environment.RESOURCES_DIR, 'sextant', 'web', 'interface.html'))
361 class ServeInterface(Resource): # all children of this class are grandchild
362 def getChild(self, name, request):
363 if not name in PROGRAM_NAMES:
364 return NoResource("The program {} was not found in the database.".format(name)
365 + "<br>If you just added that program, please go to the front page first.")
366 else:
367 return grandchild
368 root.putChild("program", ServeInterface())
369
334 # serve a dynamic webpage at /Sextant_properties to return graph properties370 # serve a dynamic webpage at /Sextant_properties to return graph properties
335 root.putChild("database_properties", GraphProperties())371 root.putChild("database_properties", GraphProperties())
336372

Subscribers

People subscribed via source and target branches