cassandra-web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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']))