cassandra-web 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +25 -0
- data/app.rb +112 -0
- data/app/helpers/json.rb +178 -0
- data/app/helpers/sse.rb +60 -0
- data/app/public/css/bootstrap-theme.css +442 -0
- data/app/public/css/bootstrap.css +6203 -0
- data/app/public/css/codemirror-solarized.css +170 -0
- data/app/public/css/codemirror.css +301 -0
- data/app/public/css/prism.css +124 -0
- data/app/public/css/style.css +30 -0
- data/app/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/app/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/app/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/app/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/app/public/html/404.html +1 -0
- data/app/public/html/execute.html +112 -0
- data/app/public/html/index.html +40 -0
- data/app/public/html/keyspace.html +40 -0
- data/app/public/html/table.html +67 -0
- data/app/public/js/angular-filter.min.js +6 -0
- data/app/public/js/cassandra.js +478 -0
- data/app/public/js/codemirror-sql.js +392 -0
- data/app/public/js/codemirror.js +7831 -0
- data/app/public/js/prism.js +475 -0
- data/app/public/js/prism.min.js +3 -0
- data/app/public/js/ui-bootstrap-tpls.min.js +10 -0
- data/app/public/js/ui-codemirror.js +126 -0
- data/app/public/main.html +96 -0
- data/bin/cassandra-web +89 -0
- metadata +174 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
<h1 class="page-header">Cluster Status</h1>
|
2
|
+
<div>
|
3
|
+
<h2>Hosts</h2>
|
4
|
+
<dl>
|
5
|
+
<dt ng-repeat-start="(datacenter, hosts) in cluster.hosts | groupBy: 'datacenter'">Datacenter: {{datacenter}}</dt>
|
6
|
+
<dd ng-repeat-end>
|
7
|
+
<table class="table table-striped table-condensed">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>ip</th>
|
11
|
+
<th>id</th>
|
12
|
+
<th>rack</th>
|
13
|
+
<th>version</th>
|
14
|
+
<th>status</th>
|
15
|
+
</tr>
|
16
|
+
</thead>
|
17
|
+
<tbody>
|
18
|
+
<tr ng-repeat="host in hosts" class="{{host_status_class(host.status)}}">
|
19
|
+
<td>{{host.ip}}</td>
|
20
|
+
<td>{{host.id}}</td>
|
21
|
+
<td>{{host.rack}}</td>
|
22
|
+
<td>{{host.release_version}}</td>
|
23
|
+
<td>{{host.status}}</td>
|
24
|
+
</tr>
|
25
|
+
</tbody>
|
26
|
+
</table>
|
27
|
+
</dd>
|
28
|
+
</dl>
|
29
|
+
</div>
|
30
|
+
<div>
|
31
|
+
<h2>Kespaces</h2>
|
32
|
+
<dl>
|
33
|
+
<dt ng-repeat-start="keyspace in cluster.keyspaces">
|
34
|
+
<a href="/{{keyspace.name}}">{{keyspace.name}}</a>
|
35
|
+
</dt>
|
36
|
+
<dd ng-repeat-end>
|
37
|
+
<pre class="highlight"><code-highlight language="cql" code="{{keyspace.cql}}" /></pre>
|
38
|
+
</dd>
|
39
|
+
</dl>
|
40
|
+
</div>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<h1 class="page-header">Keyspace: {{keyspace.name}}</h1>
|
2
|
+
<tabset>
|
3
|
+
<tab>
|
4
|
+
<tab-heading>Tables</tab-heading>
|
5
|
+
<table class="table table-striped table-hover">
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th>Name</th>
|
9
|
+
<th class="table-actions">Actions</th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<tr ng-repeat="table in keyspace.tables" ng-controller="actions">
|
14
|
+
<td><a href="/{{keyspace.name}}/{{table.name}}">{{table.name}}</a></td>
|
15
|
+
<td>
|
16
|
+
<button type="button" class="btn btn-xs btn-danger" ng-click="drop(keyspace.name, table.name)" ng-disabled="disabled"><span class="glyphicon glyphicon-minus"></span> Delete</button>
|
17
|
+
<a class="text-danger" ng-show="error" tooltip="{{error.message}}" tooltip-trigger="mouseenter" tooltip-placement="left"><span class="glyphicon glyphicon-exclamation-sign"></span></a>
|
18
|
+
</td>
|
19
|
+
</tr>
|
20
|
+
</tbody>
|
21
|
+
<tfoot>
|
22
|
+
<tr>
|
23
|
+
<td>Total: {{keyspace.tables.length}} tables</td>
|
24
|
+
<td>
|
25
|
+
<button type="button" class="btn btn-xs btn-success" ng-click="show_execute_form('CREATE TABLE ' + keyspace.name + '.<table> (
|
26
|
+
<column> <type>,
|
27
|
+
PRIMARY KEY (<column>)
|
28
|
+
)')"><span class="glyphicon glyphicon-plus"></span> Create</button>
|
29
|
+
</td>
|
30
|
+
</tr>
|
31
|
+
</tfoot>
|
32
|
+
</table>
|
33
|
+
</tab>
|
34
|
+
<tab>
|
35
|
+
<tab-heading>Definition</tab-heading>
|
36
|
+
<p>
|
37
|
+
<pre class="highlight"><code-highlight language="cql" code="{{keyspace.cql}}" /></pre>
|
38
|
+
</p>
|
39
|
+
</tab>
|
40
|
+
</tabset>
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<h1 class="page-header">Table: {{keyspace.name}}.{{table.name}}</h1>
|
2
|
+
<tabset>
|
3
|
+
<tab>
|
4
|
+
<tab-heading>Rows <span class="badge">{{result.rows.length}}</span></tab-heading>
|
5
|
+
<table class="table table-striped table-hover">
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th ng-repeat="column in table.columns">{{column.name}}</th>
|
9
|
+
<th class="row-actions">Actions</th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<tr ng-repeat="row in result.rows">
|
14
|
+
<td ng-repeat="column in table.columns">
|
15
|
+
{{row[column.name]}}
|
16
|
+
</td>
|
17
|
+
<td>
|
18
|
+
<div class="btn-group">
|
19
|
+
<button type="button" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> Edit</button>
|
20
|
+
<button type="button" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-minus"></span> Delete</button>
|
21
|
+
</div>
|
22
|
+
</td>
|
23
|
+
</tr>
|
24
|
+
</tbody>
|
25
|
+
<tfoot>
|
26
|
+
<tr>
|
27
|
+
<td colspan="{{table.columns.length}}">
|
28
|
+
<span ng-show="!result && !error">Loading...</span>
|
29
|
+
<span ng-show="result">Total: {{result.rows.length}} results</span>
|
30
|
+
<dl ng-show="error">
|
31
|
+
<dt>{{error.class}}: {{error.message}}</dt>
|
32
|
+
<dd ng-repeat="entry in error.trace track by $index">{{entry}}</dd>
|
33
|
+
</dl>
|
34
|
+
</td>
|
35
|
+
<td>
|
36
|
+
<button type="button" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-plus"></span> Create</button>
|
37
|
+
</td>
|
38
|
+
</tr>
|
39
|
+
</tfoot>
|
40
|
+
</table>
|
41
|
+
</tab>
|
42
|
+
<tab heading="Columns">
|
43
|
+
<table class="table">
|
44
|
+
<thead>
|
45
|
+
<tr>
|
46
|
+
<th>Name</th>
|
47
|
+
<th>Type</th>
|
48
|
+
<th>Order</th>
|
49
|
+
<th>Options</th>
|
50
|
+
</tr>
|
51
|
+
<thead>
|
52
|
+
<tbody>
|
53
|
+
<tr ng-repeat="column in table.columns">
|
54
|
+
<td>{{column.name}}</td>
|
55
|
+
<td>{{column.type}}</td>
|
56
|
+
<td>{{column.order}}</td>
|
57
|
+
<td>{{column.options}}</td>
|
58
|
+
</tr>
|
59
|
+
</tbody>
|
60
|
+
</table>
|
61
|
+
</tab>
|
62
|
+
<tab heading="Definition">
|
63
|
+
<p>
|
64
|
+
<pre class="highlight"><code-highlight language="cql" code="{{table.cql}}" /></pre>
|
65
|
+
</p>
|
66
|
+
</tab>
|
67
|
+
</tabset>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
/**
|
2
|
+
* Bunch of useful filters for angularJS
|
3
|
+
* @version v0.4.5 - 2014-09-08 * @link https://github.com/a8m/angular-filter
|
4
|
+
* @author Ariel Mashraki <ariel@mashraki.co.il>
|
5
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
6
|
+
*/!function(a,b,c){"use strict";function d(a){return s(a)?a:Object.keys(a).map(function(b){return a[b]})}function e(a){return null===a}function f(a,b){var c=Object.keys(a);return-1==c.map(function(c){return!(!b[c]||b[c]!=a[c])}).indexOf(!1)}function g(a,b){if(""===b)return a;var c=a.indexOf(b.charAt(0));return-1===c?!1:g(a.substr(c+1),b.substr(1))}function h(a,b,c){var d,e=~~d;return d=a.filter(function(a){var d=m(c)?b>e&&c(a):b>e;return e=d?e+1:e,d}),2>e?d[0]:d}function i(a){return function(b,c){return b=r(b)?d(b):b,!s(b)||n(c)?!0:b.some(function(b){return r(b)||o(c)?a(c)(b):b===c})}}function j(a,b){return b=b||0,b>=a.length?a:s(a[b])?j(a.slice(0,b).concat(a[b],a.slice(b+1)),b):j(a,b+1)}function k(a){return function(b,c){function e(a,b){return n(b)?!1:a.some(function(a){return w(a,b)})}if(b=r(b)?d(b):b,!s(b))return b;var f=[],g=a(c);return b.filter(n(c)?function(a,b,c){return c.indexOf(a)===b}:function(a){var b=g(a);return e(f,b)?!1:(f.push(b),!0)})}}function l(a,b,c){return b?a+c+l(a,--b,c):a}var m=b.isDefined,n=b.isUndefined,o=b.isFunction,p=b.isString,q=b.isNumber,r=b.isObject,s=b.isArray,t=b.forEach,u=b.extend,v=b.copy,w=b.equals;String.prototype.contains||(String.prototype.contains=function(){return-1!==String.prototype.indexOf.apply(this,arguments)}),b.module("a8m.angular",[]).filter("isUndefined",function(){return function(a){return b.isUndefined(a)}}).filter("isDefined",function(){return function(a){return b.isDefined(a)}}).filter("isFunction",function(){return function(a){return b.isFunction(a)}}).filter("isString",function(){return function(a){return b.isString(a)}}).filter("isNumber",function(){return function(a){return b.isNumber(a)}}).filter("isArray",function(){return function(a){return b.isArray(a)}}).filter("isObject",function(){return function(a){return b.isObject(a)}}).filter("isEqual",function(){return function(a,c){return b.equals(a,c)}}),b.module("a8m.is-null",[]).filter("isNull",function(){return function(a){return e(a)}}),b.module("a8m.after-where",[]).filter("afterWhere",function(){return function(a,b){if(a=r(a)?d(a):a,!s(a)||n(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(-1===c?0:c)}}),b.module("a8m.after",[]).filter("after",function(){return function(a,b){return a=r(a)?d(a):a,s(a)?a.slice(b):a}}),b.module("a8m.before-where",[]).filter("beforeWhere",function(){return function(a,b){if(a=r(a)?d(a):a,!s(a)||n(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(0,-1===c?a.length:++c)}}),b.module("a8m.before",[]).filter("before",function(){return function(a,b){return a=r(a)?d(a):a,s(a)?a.slice(0,b?--b:b):a}}),b.module("a8m.concat",[]).filter("concat",[function(){return function(a,b){if(n(b))return a;if(s(a))return a.concat(r(b)?d(b):b);if(r(a)){var c=d(a);return c.concat(r(b)?d(b):b)}return a}}]),b.module("a8m.contains",[]).filter({contains:["$parse",i],some:["$parse",i]}),b.module("a8m.count-by",[]).filter("countBy",["$parse",function(a){return function(b,c){var e,f={},g=a(c);return b=r(b)?d(b):b,!s(b)||n(c)?b:(b.forEach(function(a){e=g(a),f[e]||(f[e]=0),f[e]++}),f)}}]),b.module("a8m.every",[]).filter("every",["$parse",function(a){return function(b,c){return b=r(b)?d(b):b,!s(b)||n(c)?!0:b.every(function(b){return r(b)||o(c)?a(c)(b):b===c})}}]),b.module("a8m.filter-by",[]).filter("filterBy",["$parse",function(a){return function(b,e,f){var g;return f=p(f)||q(f)?String(f).toLowerCase():c,b=r(b)?d(b):b,!s(b)||n(f)?b:b.filter(function(b){return e.some(function(c){if(~c.indexOf("+")){var d=c.replace(new RegExp("\\s","g"),"").split("+");g=d.reduce(function(c,d,e){return 1===e?a(c)(b)+" "+a(d)(b):c+" "+a(d)(b)})}else g=a(c)(b);return p(g)||q(g)?String(g).toLowerCase().contains(f):!1})})}}]),b.module("a8m.first",[]).filter("first",["$parse",function(a){return function(b){var e,f,g;return b=r(b)?d(b):b,s(b)?(g=Array.prototype.slice.call(arguments,1),e=q(g[0])?g[0]:1,f=q(g[0])?q(g[1])?c:g[1]:g[0],h(b,e,f?a(f):f)):b}}]),b.module("a8m.flatten",[]).filter("flatten",function(){return function(a,b){return b=b||!1,a=r(a)?d(a):a,s(a)?b?[].concat.apply([],a):j(a,0):a}}),b.module("a8m.fuzzy-by",[]).filter("fuzzyBy",["$parse",function(a){return function(b,c,e,f){var h,i,j=f||!1;return b=r(b)?d(b):b,!s(b)||n(c)||n(e)?b:(i=a(c),b.filter(function(a){return h=i(a),p(h)?(h=j?h:h.toLowerCase(),e=j?e:e.toLowerCase(),g(h,e)!==!1):!1}))}}]),b.module("a8m.fuzzy",[]).filter("fuzzy",function(){return function(a,b,c){function e(a,b){var c,d,e=Object.keys(a);return 0<e.filter(function(e){return c=a[e],d?!0:p(c)?(c=f?c:c.toLowerCase(),d=g(c,b)!==!1):!1}).length}var f=c||!1;return a=r(a)?d(a):a,!s(a)||n(b)?a:(b=f?b:b.toLowerCase(),a.filter(function(a){return p(a)?(a=f?a:a.toLowerCase(),g(a,b)!==!1):r(a)?e(a,b):!1}))}}),b.module("a8m.group-by",["a8m.filter-watcher"]).filter("groupBy",["$parse","filterWatcher",function(a,b){return function(c,d){var e,f,g=a(d);return!r(c)||n(d)?c:(e=b.$watch("groupBy",c),t(c,function(a){f=g(a),e[f]||(e[f]=[]),-1===e[f].indexOf(a)&&e[f].push(a)}),b.$destroy("groupBy",c),e)}}]),b.module("a8m.is-empty",[]).filter("isEmpty",function(){return function(a){return r(a)?!d(a).length:!a.length}}),b.module("a8m.last",[]).filter("last",["$parse",function(a){return function(b){var e,f,g,i,j=v(b);return j=r(j)?d(j):j,s(j)?(g=Array.prototype.slice.call(arguments,1),e=q(g[0])?g[0]:1,f=q(g[0])?q(g[1])?c:g[1]:g[0],s(i=h(j.reverse(),e,f?a(f):f))?i.reverse():i):j}}]),b.module("a8m.map",[]).filter("map",["$parse",function(a){return function(b,c){return b=r(b)?d(b):b,!s(b)||n(c)?b:b.map(function(b){return a(c)(b)})}}]),b.module("a8m.omit",[]).filter("omit",["$parse",function(a){return function(b,c){return b=r(b)?d(b):b,!s(b)||n(c)?b:b.filter(function(b){return!a(c)(b)})}}]),b.module("a8m.pick",[]).filter("pick",["$parse",function(a){return function(b,c){return b=r(b)?d(b):b,!s(b)||n(c)?b:b.filter(function(b){return a(c)(b)})}}]),b.module("a8m.remove-with",[]).filter("removeWith",function(){return function(a,b){return n(b)?a:(a=r(a)?d(a):a,a.filter(function(a){return!f(b,a)}))}}),b.module("a8m.remove",[]).filter("remove",function(){return function(a){a=r(a)?d(a):a;var b=Array.prototype.slice.call(arguments,1);return s(a)?a.filter(function(a){return!b.some(function(b){return w(b,a)})}):a}}),b.module("a8m.reverse",[]).filter("reverse",[function(){return function(a){return a=r(a)?d(a):a,p(a)?a.split("").reverse().join(""):s(a)?a.reverse():a}}]),b.module("a8m.search-field",[]).filter("searchField",["$parse",function(a){return function(b){var c,e;b=r(b)?d(b):b;var f=Array.prototype.slice.call(arguments,1);return s(b)&&f.length?b.map(function(b){return e=f.map(function(d){return(c=a(d))(b)}).join(" "),u(b,{searchField:e})}):b}}]),b.module("a8m.to-array",[]).filter("toArray",function(){return function(a,b){return r(a)?b?Object.keys(a).map(function(b){return u(a[b],{$key:b})}):d(a):a}}),b.module("a8m.unique",[]).filter({unique:["$parse",k],uniq:["$parse",k]}),b.module("a8m.where",[]).filter("where",function(){return function(a,b){return n(b)?a:(a=r(a)?d(a):a,a.filter(function(a){return f(b,a)}))}}),b.module("a8m.xor",[]).filter("xor",["$parse",function(a){return function(b,c,e){function f(b,c){var d=a(e);return c.some(function(a){return e?w(d(a),d(b)):w(a,b)})}return e=e||!1,b=r(b)?d(b):b,c=r(c)?d(c):c,s(b)&&s(c)?b.concat(c).filter(function(a){return!(f(a,b)&&f(a,c))}):b}}]),b.module("a8m.math",[]).factory("$math",["$window",function(a){return a.Math}]),b.module("a8m.math.max",["a8m.math"]).filter("max",["$math",function(a){return function(b){return s(b)?a.max.apply(a,b):b}}]),b.module("a8m.math.min",["a8m.math"]).filter("min",["$math",function(a){return function(b){return s(b)?a.min.apply(a,b):b}}]),b.module("a8m.math.percent",["a8m.math"]).filter("percent",["$math","$window",function(a,b){return function(c,d,e){var f=p(c)?b.Number(c):c;return d=d||100,e=e||!1,!q(f)||b.isNaN(f)?c:e?a.round(f/d*100):f/d*100}}]),b.module("a8m.math.radix",[]).filter("radix",function(){return function(a,b){var c=/^[2-9]$|^[1-2]\d$|^3[0-6]$/;return q(a)&&c.test(b)?a.toString(b).toUpperCase():a}}),b.module("a8m.math.sum",[]).filter("sum",function(){return function(a,b){return s(a)?a.reduce(function(a,b){return a+b},b||0):a}}),b.module("a8m.ends-with",[]).filter("endsWith",function(){return function(a,b,c){var d,e=c||!1;return!p(a)||n(b)?a:(a=e?a:a.toLowerCase(),d=a.length-b.length,-1!==a.indexOf(e?b:b.toLowerCase(),d))}}),b.module("a8m.ltrim",[]).filter("ltrim",function(){return function(a,b){var c=b||"\\s";return p(a)?a.replace(new RegExp("^"+c+"+"),""):a}}),b.module("a8m.repeat",[]).filter("repeat",[function(){return function(a,b,c){var d=~~b;return p(a)&&d?l(a,--b,c||""):a}}]),b.module("a8m.rtrim",[]).filter("rtrim",function(){return function(a,b){var c=b||"\\s";return p(a)?a.replace(new RegExp(c+"+$"),""):a}}),b.module("a8m.slugify",[]).filter("slugify",[function(){return function(a,b){var c=b||"-";return p(a)?a.toLowerCase().replace(/\s+/g,c):a}}]),b.module("a8m.starts-with",[]).filter("startsWith",function(){return function(a,b,c){var d=c||!1;return!p(a)||n(b)?a:(a=d?a:a.toLowerCase(),!a.indexOf(d?b:b.toLowerCase()))}}),b.module("a8m.stringular",[]).filter("stringular",function(){return function(a){var b=Array.prototype.slice.call(arguments,1);return a.replace(/{(\d+)}/g,function(a,c){return n(b[c])?a:b[c]})}}),b.module("a8m.strip-tags",[]).filter("stripTags",function(){return function(a){return p(a)?a.replace(/<\S[^><]*>/g,""):a}}),b.module("a8m.trim",[]).filter("trim",function(){return function(a,b){var c=b||"\\s";return p(a)?a.replace(new RegExp("^"+c+"+|"+c+"+$","g"),""):a}}),b.module("a8m.truncate",[]).filter("truncate",function(){return function(a,b,c,d){return b=n(b)?a.length:b,d=d||!1,c=c||"",!p(a)||a.length<=b?a:a.substring(0,d?-1===a.indexOf(" ",b)?a.length:a.indexOf(" ",b):b)+c}}),b.module("a8m.ucfirst",[]).filter("ucfirst",[function(){return function(a){return b.isString(a)?a.split(" ").map(function(a){return a.charAt(0).toUpperCase()+a.substring(1)}).join(" "):a}}]),b.module("a8m.uri-encode",[]).filter("uriEncode",["$window",function(a){return function(b){return p(b)?a.encodeURI(b):b}}]),b.module("a8m.wrap",[]).filter("wrap",function(){return function(a,b,c){return!p(a)||n(b)?a:[b,a,c||b].join("")}}),b.module("a8m.filter-watcher",[]).provider("filterWatcher",function(){var a="_$$";this.setPrefix=function(b){return a=b,this},this.$get=["$window",function(b){function c(b){return a+b}function d(a,b){return m(b[a])}function e(a,b){var e=c(a);return d(e,b)||Object.defineProperty(b,e,{enumerable:!1,configurable:!0,value:{}}),b[e]}function f(a,b){return g(function(){delete b[c(a)]})}var g=b.setTimeout;return{$watch:e,$destroy:f}}]}),b.module("angular.filter",["a8m.ucfirst","a8m.uri-encode","a8m.slugify","a8m.strip-tags","a8m.stringular","a8m.truncate","a8m.starts-with","a8m.ends-with","a8m.wrap","a8m.trim","a8m.ltrim","a8m.rtrim","a8m.repeat","a8m.to-array","a8m.concat","a8m.contains","a8m.unique","a8m.is-empty","a8m.after","a8m.after-where","a8m.before","a8m.before-where","a8m.where","a8m.reverse","a8m.remove","a8m.remove-with","a8m.group-by","a8m.count-by","a8m.search-field","a8m.fuzzy-by","a8m.fuzzy","a8m.omit","a8m.pick","a8m.every","a8m.filter-by","a8m.xor","a8m.map","a8m.first","a8m.last","a8m.flatten","a8m.math","a8m.math.max","a8m.math.min","a8m.math.percent","a8m.math.radix","a8m.math.sum","a8m.angular","a8m.is-null","a8m.filter-watcher"])}(window,window.angular);
|
@@ -0,0 +1,478 @@
|
|
1
|
+
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
|
2
|
+
if (!Object.keys) {
|
3
|
+
Object.keys = (function () {
|
4
|
+
'use strict';
|
5
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty,
|
6
|
+
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
|
7
|
+
dontEnums = [
|
8
|
+
'toString',
|
9
|
+
'toLocaleString',
|
10
|
+
'valueOf',
|
11
|
+
'hasOwnProperty',
|
12
|
+
'isPrototypeOf',
|
13
|
+
'propertyIsEnumerable',
|
14
|
+
'constructor'
|
15
|
+
],
|
16
|
+
dontEnumsLength = dontEnums.length;
|
17
|
+
|
18
|
+
return function (obj) {
|
19
|
+
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
|
20
|
+
throw new TypeError('Object.keys called on non-object');
|
21
|
+
}
|
22
|
+
|
23
|
+
var result = [], prop, i;
|
24
|
+
|
25
|
+
for (prop in obj) {
|
26
|
+
if (hasOwnProperty.call(obj, prop)) {
|
27
|
+
result.push(prop);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
if (hasDontEnumBug) {
|
32
|
+
for (i = 0; i < dontEnumsLength; i++) {
|
33
|
+
if (hasOwnProperty.call(obj, dontEnums[i])) {
|
34
|
+
result.push(dontEnums[i]);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return result;
|
39
|
+
};
|
40
|
+
}());
|
41
|
+
}
|
42
|
+
|
43
|
+
!(function(app) {
|
44
|
+
app.config([
|
45
|
+
'$routeProvider',
|
46
|
+
'$locationProvider',
|
47
|
+
'$rootScopeProvider',
|
48
|
+
'$logProvider',
|
49
|
+
'$compileProvider',
|
50
|
+
function($routeProvider, $locationProvider, $rootScopeProvider, $logProvider, $compileProvider) {
|
51
|
+
$routeProvider
|
52
|
+
.when('/', {
|
53
|
+
templateUrl: '/html/index.html',
|
54
|
+
})
|
55
|
+
.when('/:keyspace', {
|
56
|
+
templateUrl: '/html/keyspace.html',
|
57
|
+
controller: 'keyspace',
|
58
|
+
resolve: {cluster: 'cluster'}
|
59
|
+
})
|
60
|
+
.when('/:keyspace/:table', {
|
61
|
+
templateUrl: '/html/table.html',
|
62
|
+
controller: 'table',
|
63
|
+
resolve: {cluster: 'cluster'}
|
64
|
+
})
|
65
|
+
.otherwise({redirect:'/'})
|
66
|
+
|
67
|
+
$locationProvider.html5Mode(true)
|
68
|
+
$rootScopeProvider.digestTtl(10000)
|
69
|
+
$logProvider.debugEnabled(true)
|
70
|
+
$compileProvider.debugInfoEnabled(true)
|
71
|
+
}
|
72
|
+
])
|
73
|
+
|
74
|
+
app.factory('cluster', [
|
75
|
+
'$http',
|
76
|
+
'$rootScope',
|
77
|
+
'$q',
|
78
|
+
function($http, $rootScope, $q) {
|
79
|
+
var cluster = {
|
80
|
+
keyspaces: null,
|
81
|
+
hosts: null,
|
82
|
+
keyspace: null,
|
83
|
+
execute: function(statement, options) {
|
84
|
+
var deferred = $q.defer();
|
85
|
+
options = options || {}
|
86
|
+
|
87
|
+
$http({
|
88
|
+
method: 'POST',
|
89
|
+
url: '/execute',
|
90
|
+
data: {
|
91
|
+
statement: statement,
|
92
|
+
options: options
|
93
|
+
}
|
94
|
+
})
|
95
|
+
.success(function(data, status, headers, config) {
|
96
|
+
deferred.resolve(data)
|
97
|
+
})
|
98
|
+
.error(function(data, status, headers, config) {
|
99
|
+
deferred.reject(data)
|
100
|
+
})
|
101
|
+
|
102
|
+
return deferred.promise
|
103
|
+
}
|
104
|
+
}
|
105
|
+
var resolved = false
|
106
|
+
var deferred = $q.defer()
|
107
|
+
|
108
|
+
var events = new EventSource('/events');
|
109
|
+
|
110
|
+
events.onopen = function(e) {
|
111
|
+
updateCluster();
|
112
|
+
return false;
|
113
|
+
}
|
114
|
+
|
115
|
+
$rootScope.$on('$destroy', function() {
|
116
|
+
events.close();
|
117
|
+
})
|
118
|
+
|
119
|
+
var updateCluster = function() {
|
120
|
+
$http({method: 'GET', url: '/keyspaces'})
|
121
|
+
.success(function(data, status, headers, config) {
|
122
|
+
cluster.keyspaces = data
|
123
|
+
|
124
|
+
events.addEventListener('keyspace_created', addKeyspace, false);
|
125
|
+
events.addEventListener('keyspace_changed', updateKeyspace, false);
|
126
|
+
events.addEventListener('keyspace_dropped', removeKeyspace, false);
|
127
|
+
|
128
|
+
if (!resolved && cluster.keyspaces && cluster.hosts) {
|
129
|
+
resolved = true
|
130
|
+
deferred.resolve(cluster)
|
131
|
+
}
|
132
|
+
})
|
133
|
+
.error(function(data, status, headers, config) {
|
134
|
+
console.log('ERROR', data);
|
135
|
+
})
|
136
|
+
|
137
|
+
$http({method: 'GET', url: '/hosts'})
|
138
|
+
.success(function(data, status, headers, config) {
|
139
|
+
cluster.hosts = data
|
140
|
+
|
141
|
+
events.addEventListener('host_found', addHost, false);
|
142
|
+
events.addEventListener('host_up', updateHost, false);
|
143
|
+
events.addEventListener('host_down', updateHost, false);
|
144
|
+
events.addEventListener('host_lost', removeHost, false);
|
145
|
+
|
146
|
+
if (!resolved && cluster.keyspaces && cluster.hosts) {
|
147
|
+
resolved = true
|
148
|
+
deferred.resolve(cluster)
|
149
|
+
}
|
150
|
+
})
|
151
|
+
.error(function(data, status, headers, config) {
|
152
|
+
console.log('ERROR', data);
|
153
|
+
})
|
154
|
+
}
|
155
|
+
|
156
|
+
var addHost = function(event) {
|
157
|
+
var host = JSON.parse(event.data)
|
158
|
+
|
159
|
+
$rootScope.$apply(function() {
|
160
|
+
$rootScope.$broadcast('host.created', host)
|
161
|
+
cluster.hosts.push(host)
|
162
|
+
})
|
163
|
+
}
|
164
|
+
|
165
|
+
var updateHost = function(event) {
|
166
|
+
var host = JSON.parse(event.data)
|
167
|
+
|
168
|
+
$rootScope.$apply(function() {
|
169
|
+
$rootScope.$broadcast('host.updated', host)
|
170
|
+
angular.forEach(cluster.hosts, function(h, index) {
|
171
|
+
if (host.ip == h.ip) {
|
172
|
+
angular.forEach(host, function(value, key) {
|
173
|
+
cluster.hosts[index][key] = value
|
174
|
+
})
|
175
|
+
}
|
176
|
+
})
|
177
|
+
})
|
178
|
+
}
|
179
|
+
|
180
|
+
var removeHost = function(event) {
|
181
|
+
var host = JSON.parse(event.data)
|
182
|
+
|
183
|
+
$rootScope.$apply(function() {
|
184
|
+
$rootScope.$broadcast('host.removed', host)
|
185
|
+
angular.forEach(cluster.hosts, function(h, index) {
|
186
|
+
if (host.ip == h.ip) {
|
187
|
+
cluster.hosts.splice(index, 1)
|
188
|
+
}
|
189
|
+
})
|
190
|
+
})
|
191
|
+
}
|
192
|
+
|
193
|
+
var addKeyspace = function(event) {
|
194
|
+
var keyspace = JSON.parse(event.data)
|
195
|
+
|
196
|
+
$rootScope.$apply(function() {
|
197
|
+
$rootScope.$broadcast('keyspace.created', keyspace)
|
198
|
+
cluster.keyspaces.push(keyspace)
|
199
|
+
})
|
200
|
+
}
|
201
|
+
|
202
|
+
var updateKeyspace = function(event) {
|
203
|
+
var keyspace = JSON.parse(event.data)
|
204
|
+
|
205
|
+
$rootScope.$apply(function() {
|
206
|
+
$rootScope.$broadcast('keyspace.updated', keyspace)
|
207
|
+
angular.forEach(cluster.keyspaces, function(k, index) {
|
208
|
+
if (keyspace.name == k.name) {
|
209
|
+
angular.forEach(keyspace, function(value, key) {
|
210
|
+
cluster.keyspaces[index][key] = value
|
211
|
+
})
|
212
|
+
}
|
213
|
+
})
|
214
|
+
})
|
215
|
+
}
|
216
|
+
|
217
|
+
var removeKeyspace = function(event) {
|
218
|
+
var keyspace = JSON.parse(event.data)
|
219
|
+
|
220
|
+
$rootScope.$apply(function() {
|
221
|
+
$rootScope.$broadcast('keyspace.removed', keyspace)
|
222
|
+
angular.forEach(cluster.keyspaces, function(k, index) {
|
223
|
+
if (keyspace.name == k.name) {
|
224
|
+
cluster.keyspaces.splice(index, 1)
|
225
|
+
}
|
226
|
+
})
|
227
|
+
})
|
228
|
+
}
|
229
|
+
|
230
|
+
return deferred.promise
|
231
|
+
}
|
232
|
+
])
|
233
|
+
|
234
|
+
app.factory('escapeIdentifier', [
|
235
|
+
function() {
|
236
|
+
var re = /[a-z][a-z0-9_]*/
|
237
|
+
|
238
|
+
return function(id) {
|
239
|
+
var matches = id.match(re)
|
240
|
+
if (matches.length == 1 && matches[0].length == id.length) {
|
241
|
+
return id
|
242
|
+
}
|
243
|
+
return '"' + id + '"'
|
244
|
+
}
|
245
|
+
}
|
246
|
+
])
|
247
|
+
|
248
|
+
app.directive('codeHighlight',[
|
249
|
+
'$interpolate',
|
250
|
+
'$compile',
|
251
|
+
function ($interpolate, $compile) {
|
252
|
+
return {
|
253
|
+
restrict: 'E',
|
254
|
+
template: '<code ng-transclude></code>',
|
255
|
+
replace: true,
|
256
|
+
transclude: true,
|
257
|
+
link: function (scope, el, attrs) {
|
258
|
+
var language = Prism.languages[attrs.language]
|
259
|
+
|
260
|
+
attrs.$observe('code', function(code) {
|
261
|
+
el.html(Prism.highlight(code, language))
|
262
|
+
})
|
263
|
+
}
|
264
|
+
}
|
265
|
+
}
|
266
|
+
])
|
267
|
+
|
268
|
+
app.controller('main', [
|
269
|
+
'$scope',
|
270
|
+
'cluster',
|
271
|
+
'$routeParams',
|
272
|
+
'$modal',
|
273
|
+
function($scope, cluster, $routeParams, $modal) {
|
274
|
+
cluster.then(
|
275
|
+
function(cluster) {
|
276
|
+
$scope.cluster = cluster
|
277
|
+
}
|
278
|
+
)
|
279
|
+
|
280
|
+
$scope.host_status_class = function(status) {
|
281
|
+
if (status == 'up') {
|
282
|
+
return 'success'
|
283
|
+
}
|
284
|
+
|
285
|
+
return 'danger'
|
286
|
+
}
|
287
|
+
|
288
|
+
$scope.keyspace_class = function(keyspace) {
|
289
|
+
if ($routeParams.keyspace && $routeParams.keyspace == keyspace.name) {
|
290
|
+
return 'active'
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
$scope.show_execute_form = function(statement) {
|
295
|
+
var childScope = $scope.$new()
|
296
|
+
|
297
|
+
childScope.statement = {cql: statement}
|
298
|
+
|
299
|
+
return $modal.open({
|
300
|
+
templateUrl: '/html/execute.html',
|
301
|
+
controller: 'execute',
|
302
|
+
size: 'lg',
|
303
|
+
scope: childScope
|
304
|
+
})
|
305
|
+
}
|
306
|
+
}
|
307
|
+
])
|
308
|
+
|
309
|
+
app.controller('execute', [
|
310
|
+
'$scope',
|
311
|
+
function($scope) {
|
312
|
+
$scope.disabled = false
|
313
|
+
$scope.options = $scope.options || {
|
314
|
+
trace: false,
|
315
|
+
consistency: 'one'
|
316
|
+
}
|
317
|
+
$scope.statement = $scope.statement || {
|
318
|
+
cql: ''
|
319
|
+
}
|
320
|
+
$scope.consistencies = [
|
321
|
+
"any",
|
322
|
+
"one",
|
323
|
+
"two",
|
324
|
+
"three",
|
325
|
+
"quorum",
|
326
|
+
"all",
|
327
|
+
"local_quorum",
|
328
|
+
"each_quorum",
|
329
|
+
"serial",
|
330
|
+
"local_serial",
|
331
|
+
"local_one"
|
332
|
+
]
|
333
|
+
|
334
|
+
$scope.execute = function() {
|
335
|
+
$scope.disabled = true
|
336
|
+
|
337
|
+
$scope.cluster.execute($scope.statement.cql, $scope.options)
|
338
|
+
.then(
|
339
|
+
function(result) {
|
340
|
+
$scope.disabled = false
|
341
|
+
$scope.result = result;
|
342
|
+
},
|
343
|
+
function(error) {
|
344
|
+
$scope.error = error
|
345
|
+
}
|
346
|
+
)
|
347
|
+
}
|
348
|
+
|
349
|
+
$scope.$watch('options.consistency', function(consistency) {
|
350
|
+
if ($scope.error) {
|
351
|
+
$scope.disabled = false
|
352
|
+
delete $scope.error
|
353
|
+
}
|
354
|
+
})
|
355
|
+
|
356
|
+
$scope.$watch('statement.cql', function(cql) {
|
357
|
+
if ($scope.error) {
|
358
|
+
$scope.disabled = false
|
359
|
+
delete $scope.error
|
360
|
+
}
|
361
|
+
})
|
362
|
+
}
|
363
|
+
])
|
364
|
+
|
365
|
+
app.controller('keyspace', [
|
366
|
+
'$scope',
|
367
|
+
'cluster',
|
368
|
+
'$routeParams',
|
369
|
+
'$location',
|
370
|
+
function($scope, cluster, $routeParams, $location) {
|
371
|
+
cluster.keyspaces.forEach(function(keyspace) {
|
372
|
+
if ($routeParams.keyspace == keyspace.name) {
|
373
|
+
$scope.keyspace = keyspace
|
374
|
+
}
|
375
|
+
})
|
376
|
+
|
377
|
+
if (!$scope.keyspace) {
|
378
|
+
$location.path('/')
|
379
|
+
}
|
380
|
+
|
381
|
+
$scope.$on('keyspace.removed', function(event, keyspace) {
|
382
|
+
if ($routeParams.keyspace == keyspace.name) {
|
383
|
+
$location.path('/')
|
384
|
+
}
|
385
|
+
})
|
386
|
+
}
|
387
|
+
])
|
388
|
+
|
389
|
+
app.controller('table', [
|
390
|
+
'$scope',
|
391
|
+
'cluster',
|
392
|
+
'$routeParams',
|
393
|
+
'$location',
|
394
|
+
'escapeIdentifier',
|
395
|
+
function($scope, cluster, $routeParams, $location, escapeIdentifier) {
|
396
|
+
cluster.keyspaces.forEach(function(keyspace) {
|
397
|
+
if ($routeParams.keyspace == keyspace.name) {
|
398
|
+
$scope.keyspace = keyspace
|
399
|
+
}
|
400
|
+
})
|
401
|
+
|
402
|
+
if (!$scope.keyspace) {
|
403
|
+
$location.path('/')
|
404
|
+
}
|
405
|
+
|
406
|
+
$scope.$on('keyspace.removed', function(event, keyspace) {
|
407
|
+
if ($routeParams.keyspace == keyspace.name) {
|
408
|
+
$location.path('/')
|
409
|
+
}
|
410
|
+
})
|
411
|
+
|
412
|
+
$scope.keyspace.tables.forEach(function(table) {
|
413
|
+
if ($routeParams.table == table.name) {
|
414
|
+
$scope.table = table
|
415
|
+
}
|
416
|
+
})
|
417
|
+
|
418
|
+
if (!$scope.table) {
|
419
|
+
$location.path('/')
|
420
|
+
}
|
421
|
+
|
422
|
+
$scope.$on('keyspace.updated', function(keyspace) {
|
423
|
+
if ($routeParams.keyspace != keyspace.name) {
|
424
|
+
return
|
425
|
+
}
|
426
|
+
|
427
|
+
var exists = false;
|
428
|
+
|
429
|
+
keyspace.tables.forEach(function(table) {
|
430
|
+
exists = exists || (table.name == $scope.table.name)
|
431
|
+
})
|
432
|
+
|
433
|
+
if (!exists) {
|
434
|
+
$location.path('/' + $scope.keyspace.name)
|
435
|
+
}
|
436
|
+
})
|
437
|
+
|
438
|
+
cluster.execute('SELECT * FROM ' + escapeIdentifier($scope.keyspace.name) + '.' + escapeIdentifier($scope.table.name))
|
439
|
+
.then(
|
440
|
+
function(result) {
|
441
|
+
$scope.result = result
|
442
|
+
},
|
443
|
+
function(error) {
|
444
|
+
$scope.error = error
|
445
|
+
}
|
446
|
+
)
|
447
|
+
}
|
448
|
+
])
|
449
|
+
|
450
|
+
app.controller('actions', [
|
451
|
+
'$scope',
|
452
|
+
'cluster',
|
453
|
+
'escapeIdentifier',
|
454
|
+
function($scope, cluster, escapeIdentifier) {
|
455
|
+
$scope.disabled = false
|
456
|
+
$scope.drop = function(keyspaceName, tableName) {
|
457
|
+
$scope.disabled = true
|
458
|
+
|
459
|
+
return cluster
|
460
|
+
.then(
|
461
|
+
function(cluster) {
|
462
|
+
return cluster
|
463
|
+
.execute('DROP TABLE ' + escapeIdentifier($scope.keyspace.name) + '.' + escapeIdentifier(tableName))
|
464
|
+
}
|
465
|
+
)
|
466
|
+
.then(
|
467
|
+
function(result) {
|
468
|
+
$scope.result = result
|
469
|
+
$scope.disabled = false
|
470
|
+
},
|
471
|
+
function(error) {
|
472
|
+
$scope.error = error
|
473
|
+
}
|
474
|
+
)
|
475
|
+
}
|
476
|
+
}
|
477
|
+
])
|
478
|
+
})(angular.module('cassandra', ['ngRoute', 'angular.filter', 'ui.bootstrap', 'ui.codemirror']))
|