cassandra-web 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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']))