1 | {{extend 'layout.html'}} |
---|
2 | <script><!-- |
---|
3 | jQuery(document).ready(function(){ |
---|
4 | jQuery("table.sortable tbody tr").mouseover( function() { |
---|
5 | jQuery(this).addClass("highlight"); }).mouseout( function() { |
---|
6 | jQuery(this).removeClass("highlight"); }); |
---|
7 | jQuery('table.sortable tbody tr:odd').addClass('odd'); |
---|
8 | jQuery('table.sortable tbody tr:even').addClass('even'); |
---|
9 | }); |
---|
10 | //--></script> |
---|
11 | |
---|
12 | <div class="row"> |
---|
13 | <div class="col-md-12"> |
---|
14 | |
---|
15 | {{if request.function=='index':}} |
---|
16 | <h2>{{=T("Available Databases and Tables")}}</h2> |
---|
17 | {{if not databases:}}{{=T("No databases in this application")}}{{pass}} |
---|
18 | <ul class="nav nav-tabs" id="myTab"> |
---|
19 | <li class="nav-item"><a href="#alltables" data-toggle="tab" class="nav-link active">Tables</a></li> |
---|
20 | <li class="nav-item"><a href="#hooks" data-toggle="tab" class="nav-link">Hooks</a></li> |
---|
21 | </ul> |
---|
22 | <div class="tab-content"> |
---|
23 | <div class="tab-pane active" id="alltables"> |
---|
24 | <table class="table table-striped"> |
---|
25 | {{for db in sorted(databases):}} |
---|
26 | {{for table in databases[db].tables:}} |
---|
27 | {{qry='%s.%s.id>0'%(db,table)}} |
---|
28 | {{tbl=databases[db][table]}} |
---|
29 | {{if hasattr(tbl,'_primarykey'):}} |
---|
30 | {{if tbl._primarykey:}} |
---|
31 | {{firstkey=tbl[tbl._primarykey[0]]}} |
---|
32 | {{if firstkey.type in ['string','text']:}} |
---|
33 | {{qry='%s.%s.%s!=""'%(db,table,firstkey.name)}} |
---|
34 | {{else:}} |
---|
35 | {{qry='%s.%s.%s>0'%(db,table,firstkey.name)}} |
---|
36 | {{pass}} |
---|
37 | {{else:}} |
---|
38 | {{qry=''}} |
---|
39 | {{pass}} |
---|
40 | {{pass}} |
---|
41 | <tr> |
---|
42 | <th style="font-size: 1.75em;"> |
---|
43 | » {{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}} |
---|
44 | </th> |
---|
45 | <td> |
---|
46 | {{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-primary")}} |
---|
47 | </td> |
---|
48 | </tr> |
---|
49 | {{pass}} |
---|
50 | {{pass}} |
---|
51 | </table> |
---|
52 | </div> |
---|
53 | <div class="tab-pane" id="hooks"> |
---|
54 | {{=LOAD('appadmin', 'hooks', ajax=True)}} |
---|
55 | </div> |
---|
56 | </div> |
---|
57 | {{elif request.function=='select':}} |
---|
58 | <h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }} |
---|
59 | </h2> |
---|
60 | {{if tb:}} |
---|
61 | <h3>{{=T('Traceback')}}</h3> |
---|
62 | <pre> |
---|
63 | {{=tb}} |
---|
64 | </pre> |
---|
65 | {{pass}} |
---|
66 | {{if table:}} |
---|
67 | {{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-primary", _role="button")}}<br/><br/> |
---|
68 | <hr /> |
---|
69 | <h3>{{=T("Rows in Table")}}</h3><br/> |
---|
70 | {{else:}} |
---|
71 | <h3>{{=T("Rows selected")}}</h3><br/> |
---|
72 | {{pass}} |
---|
73 | {{=form}} |
---|
74 | <p class="text-muted">{{=T('The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.')}}<br/> |
---|
75 | {{=T('Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.')}}<br/> |
---|
76 | {{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p> |
---|
77 | <br/><br/> |
---|
78 | <h4>{{=T("%s selected", nrows)}}</h4> |
---|
79 | {{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-primary")}}{{pass}} |
---|
80 | {{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-primary")}}{{pass}} |
---|
81 | {{if rows:}} |
---|
82 | <div style="overflow:auto; width:80%;"> |
---|
83 | {{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}} |
---|
84 | {{upload=URL('download',args=request.args[0])}} |
---|
85 | {{=SQLTABLE(rows,linkto,upload,orderby=True,_class='table table-striped table-bordered sortable')}} |
---|
86 | </div> |
---|
87 | {{pass}} |
---|
88 | <br/><br/> |
---|
89 | <hr /> |
---|
90 | <h3>{{=T("Import/Export")}}</h3><br/> |
---|
91 | <a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-primary">{{=T("export as csv file")}}</a> |
---|
92 | {{=formcsv or ''}} |
---|
93 | |
---|
94 | {{elif request.function=='insert':}} |
---|
95 | <h2>{{=T("Database")}} {{=A(request.args[0],_href=URL('index'))}} |
---|
96 | {{if hasattr(table,'_primarykey'):}} |
---|
97 | {{fieldname=table._primarykey[0]}} |
---|
98 | {{dbname=request.args[0]}} |
---|
99 | {{tablename=request.args[1]}} |
---|
100 | {{cond = table[fieldname].type in ['string','text'] and '!=""' or '>0'}} |
---|
101 | {{=T("Table")}} {{=A(tablename,_href=URL('select',args=dbname,vars=dict(query='%s.%s.%s%s'%(dbname,tablename,fieldname,cond))))}} |
---|
102 | {{else:}} |
---|
103 | {{=T("Table")}} {{=A(request.args[1],_href=URL('select',args=request.args[0],vars=dict(query='%s.%s.id>0'%tuple(request.args[:2]))))}} |
---|
104 | {{pass}} |
---|
105 | </h2> |
---|
106 | <h3>{{=T("New Record")}}</h3><br/> |
---|
107 | {{=form}} |
---|
108 | {{elif request.function=='update':}} |
---|
109 | <h2>{{=T("Database")}} {{=A(request.args[0],_href=URL('index'))}} |
---|
110 | {{if hasattr(table,'_primarykey'):}} |
---|
111 | {{fieldname=request.vars.keys()[0]}} |
---|
112 | {{dbname=request.args[0]}} |
---|
113 | {{tablename=request.args[1]}} |
---|
114 | {{cond = table[fieldname].type in ['string','text'] and '!=""' or '>0'}} |
---|
115 | {{=T("Table")}} {{=A(tablename,_href=URL('select',args=dbname,vars=dict(query='%s.%s.%s%s'%(dbname,tablename,fieldname,cond))))}} |
---|
116 | {{=T("Record")}} {{=A('%s=%s'%request.vars.items()[0],_href=URL('update',args=request.args[:2],vars=request.vars))}} |
---|
117 | {{else:}} |
---|
118 | {{=T("Table")}} {{=A(request.args[1],_href=URL('select',args=request.args[0],vars=dict(query='%s.%s.id>0'%tuple(request.args[:2]))))}} |
---|
119 | {{=T("Record id")}} {{=A(request.args[2],_href=URL('update',args=request.args[:3]))}} |
---|
120 | {{pass}} |
---|
121 | </h2> |
---|
122 | <h3>{{=T("Edit current record")}}</h3><br/><br/>{{=form}} |
---|
123 | |
---|
124 | {{elif request.function=='state':}} |
---|
125 | <h2>{{=T("Internal State")}}</h2> |
---|
126 | <h3>{{=T("Current request")}}</h3> |
---|
127 | {{=BEAUTIFY(request)}} |
---|
128 | <br/><h3>{{=T("Current response")}}</h3> |
---|
129 | {{=BEAUTIFY(response)}} |
---|
130 | <br/><h3>{{=T("Current session")}}</h3> |
---|
131 | {{=BEAUTIFY(session)}} |
---|
132 | |
---|
133 | |
---|
134 | {{elif request.function == 'ccache':}} |
---|
135 | <h2>{{T("Cache")}}</h2> |
---|
136 | <div class="list"> |
---|
137 | |
---|
138 | <div class="list-header"> |
---|
139 | <h3>{{T("Statistics")}}</h3> |
---|
140 | </div> |
---|
141 | |
---|
142 | <div class="content"> |
---|
143 | <h4>{{=T("Overview")}}</h4> |
---|
144 | <p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p> |
---|
145 | {{if total['entries'] > 0:}} |
---|
146 | <p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})", |
---|
147 | dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}} |
---|
148 | </p> |
---|
149 | <p> |
---|
150 | {{=T("Size of cache:")}} |
---|
151 | {{if object_stats:}} |
---|
152 | {{=T.M("**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}", dict(items=total['objects'], bytes=total['bytes']))}} |
---|
153 | {{if total['bytes'] > 524287:}} |
---|
154 | {{=T.M("(**%.0d MB**)", total['bytes'] / 1048576)}} |
---|
155 | {{pass}} |
---|
156 | {{else:}} |
---|
157 | {{=T.M("**not available** (requires the Python [[Pympler https://pypi.python.org/pypi/Pympler popup]] library)")}} |
---|
158 | {{pass}} |
---|
159 | </p> |
---|
160 | <p> |
---|
161 | {{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.", |
---|
162 | dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}} |
---|
163 | </p> |
---|
164 | {{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}} |
---|
165 | <div class="w2p_hidden" id="all_keys"> |
---|
166 | {{=total['keys']}} |
---|
167 | </div> |
---|
168 | <br /> |
---|
169 | {{pass}} |
---|
170 | |
---|
171 | <h4>{{=T("RAM")}}</h4> |
---|
172 | <p>{{=T.M("Number of entries: **%s**", ram['entries'])}}</p> |
---|
173 | {{if ram['entries'] > 0:}} |
---|
174 | <p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})", |
---|
175 | dict( ratio=ram['ratio'], hits=ram['hits'], misses=ram['misses']))}} |
---|
176 | </p> |
---|
177 | <p> |
---|
178 | {{=T("Size of cache:")}} |
---|
179 | {{if object_stats:}} |
---|
180 | {{=T.M("**%(items)s** items, **%(bytes)s** %%{byte(bytes)}", dict(items=ram['objects'], bytes=ram['bytes']))}} |
---|
181 | {{if ram['bytes'] > 524287:}} |
---|
182 | {{=T.M("(**%.0d MB**)", ram['bytes'] / 10485576)}} |
---|
183 | {{pass}} |
---|
184 | {{else:}} |
---|
185 | {{=T.M("``**not available**``:red (requires the Python [[Pympler https://pypi.python.org/pypi/Pympler popup]] library)")}} |
---|
186 | {{pass}} |
---|
187 | </p> |
---|
188 | <p> |
---|
189 | {{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.", |
---|
190 | dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}} |
---|
191 | </p> |
---|
192 | {{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}} |
---|
193 | <div class="w2p_hidden" id="ram_keys"> |
---|
194 | {{=ram['keys']}} |
---|
195 | </div> |
---|
196 | <br /> |
---|
197 | {{pass}} |
---|
198 | |
---|
199 | <h4>{{=T("DISK")}}</h4> |
---|
200 | <p>{{=T.M("Number of entries: **%s**", disk['entries'])}}</p> |
---|
201 | {{if disk['entries'] > 0:}} |
---|
202 | <p> |
---|
203 | {{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})", |
---|
204 | dict(ratio=disk['ratio'], hits=disk['hits'], misses=disk['misses']))}} |
---|
205 | </p> |
---|
206 | <p> |
---|
207 | {{=T("Size of cache:")}} |
---|
208 | {{if object_stats:}} |
---|
209 | {{=T.M("**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}", dict( items=disk['objects'], bytes=disk['bytes']))}} |
---|
210 | {{if disk['bytes'] > 524287:}} |
---|
211 | {{=T.M("(**%.0d MB**)", disk['bytes'] / 1048576)}} |
---|
212 | {{pass}} |
---|
213 | {{else:}} |
---|
214 | {{=T.M("``**not available**``:red (requires the Python [[Pympler https://pypi.python.org/pypi/Pympler popup]] library)")}} |
---|
215 | {{pass}} |
---|
216 | </p> |
---|
217 | <p> |
---|
218 | {{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.", |
---|
219 | dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}} |
---|
220 | </p> |
---|
221 | {{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}} |
---|
222 | <div class="w2p_hidden" id="disk_keys"> |
---|
223 | {{=disk['keys']}} |
---|
224 | </div> |
---|
225 | <br /> |
---|
226 | {{pass}} |
---|
227 | </div> |
---|
228 | |
---|
229 | <div class="list-header"> |
---|
230 | <h3>{{=T("Manage Cache")}}</h3> |
---|
231 | </div> |
---|
232 | |
---|
233 | <div class="content"> |
---|
234 | <p> |
---|
235 | {{=form}} |
---|
236 | </p> |
---|
237 | </div> |
---|
238 | </div> |
---|
239 | <div class="clear"></div> |
---|
240 | {{pass}} |
---|
241 | |
---|
242 | {{if request.function=='d3_graph_model':}} |
---|
243 | <h2>{{=T("Graph Model")}}</h2> |
---|
244 | {{if not databases:}} |
---|
245 | {{=T("No databases in this application")}} |
---|
246 | {{else:}} |
---|
247 | <div id="vis"></div> |
---|
248 | <link rel="stylesheet" href="{{=URL('admin','static','css/d3_graph.css')}}"/> |
---|
249 | <script> |
---|
250 | // Define the d3 input data |
---|
251 | {{from gluon.serializers import json }} |
---|
252 | var nodes = {{=XML(json(nodes))}}; |
---|
253 | var links = {{=XML(json(links))}}; |
---|
254 | d3_graph(); |
---|
255 | </script> |
---|
256 | {{pass}} |
---|
257 | {{pass}} |
---|
258 | |
---|
259 | {{if request.function == 'manage':}} |
---|
260 | <h2>{{=heading}}</h2> |
---|
261 | <ul class="nav nav-tabs"> |
---|
262 | {{for k, tablename in enumerate(tablenames):}} |
---|
263 | <li{{=XML(' class="active"') if k == 0 else ''}}> |
---|
264 | <a href="#table-{{=tablename}}" data-toggle="tab">{{=labels[k]}}</a> |
---|
265 | </li> |
---|
266 | {{pass}} |
---|
267 | </ul> |
---|
268 | |
---|
269 | <div class="tab-content"> |
---|
270 | {{for k, tablename in enumerate(tablenames):}} |
---|
271 | <div class="tab-pane{{=XML(' active') if k == 0 else ''}}" id="table-{{=tablename}}"> |
---|
272 | {{=LOAD(f='manage.load', args=[request.args(0), k], ajax=True)}} |
---|
273 | </div> |
---|
274 | {{pass}} |
---|
275 | </div> |
---|
276 | {{pass}} |
---|
277 | |
---|
278 | </div> |
---|
279 | </div> |
---|