| 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> |
|---|