17877adba0e7c8f5dd72bab7c3cae8db809803ed
[ccsdk/features.git] /
1 /**
2  * Copyright 2010-2013 Ben Birch
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this software except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 (function( app, i18n, joey ) {
17
18         var ui = app.ns("ui");
19         var ut = app.ns("ut");
20
21         ui.NodesView = ui.AbstractWidget.extend({
22                 defaults: {
23                         interactive: true,
24                         aliasRenderer: "list",
25                         scaleReplicas: 1,
26                         cluster: null,
27                         data: null
28                 },
29                 init: function() {
30                         this._super();
31                         this.interactive = this.config.interactive;
32                         this.cluster = this.config.cluster;
33                         this._aliasRenderFunction = {
34                                 "none": this._aliasRender_template_none,
35                                 "list": this._aliasRender_template_list,
36                                 "full": this._aliasRender_template_full
37                         }[ this.config.aliasRenderer ];
38                         this._styleSheetEl = joey({ tag: "STYLE", text: ".uiNodesView-nullReplica, .uiNodesView-replica { zoom: " + this.config.scaleReplicas + " }" });
39                         this.el = $( this._main_template( this.config.data.cluster, this.config.data.indices ) );
40                 },
41
42                 _newAliasAction_handler: function( index ) {
43                         var fields = new app.ux.FieldCollection({
44                                 fields: [
45                                         new ui.TextField({ label: i18n.text("AliasForm.AliasName"), name: "alias", require: true })
46                                 ]
47                         });
48                         var dialog = new ui.DialogPanel({
49                                 title: i18n.text("AliasForm.NewAliasForIndexName", index.name),
50                                 body: new ui.PanelForm({ fields: fields }),
51                                 onCommit: function(panel, args) {
52                                         if(fields.validate()) {
53                                                 var data = fields.getData();
54                                                 var command = {
55                                                         "actions" : [
56                                                                 { "add" : { "index" : index.name, "alias" : data["alias"] } }
57                                                         ]
58                                                 };
59                                                 this.config.cluster.post('_aliases', JSON.stringify(command), function(d) {
60                                                         dialog.close();
61                                                         alert(JSON.stringify(d));
62                                                         this.fire("redraw");
63                                                 }.bind(this) );
64                                         }
65                                 }.bind(this)
66                         }).open();
67                 },
68                 _postIndexAction_handler: function(action, index, redraw) {
69                         this.cluster.post(encodeURIComponent( index.name ) + "/" + encodeURIComponent( action ), null, function(r) {
70                                 alert(JSON.stringify(r));
71                                 redraw && this.fire("redraw");
72                         }.bind(this));
73                 },
74                 _optimizeIndex_handler: function(index) {
75                         var fields = new app.ux.FieldCollection({
76                                 fields: [
77                                         new ui.TextField({ label: i18n.text("OptimizeForm.MaxSegments"), name: "max_num_segments", value: "1", require: true }),
78                                         new ui.CheckField({ label: i18n.text("OptimizeForm.ExpungeDeletes"), name: "only_expunge_deletes", value: false }),
79                                         new ui.CheckField({ label: i18n.text("OptimizeForm.FlushAfter"), name: "flush", value: true }),
80                                         new ui.CheckField({ label: i18n.text("OptimizeForm.WaitForMerge"), name: "wait_for_merge", value: false })
81                                 ]
82                         });
83                         var dialog = new ui.DialogPanel({
84                                 title: i18n.text("OptimizeForm.OptimizeIndex", index.name),
85                                 body: new ui.PanelForm({ fields: fields }),
86                                 onCommit: function( panel, args ) {
87                                         if(fields.validate()) {
88                                                 this.cluster.post(encodeURIComponent( index.name ) + "/_optimize", fields.getData(), function(r) {
89                                                         alert(JSON.stringify(r));
90                                                 });
91                                                 dialog.close();
92                                         }
93                                 }.bind(this)
94                         }).open();
95                 },
96                 _testAnalyser_handler: function(index) {
97                         this.cluster.get(encodeURIComponent( index.name ) + "/_analyze?text=" + encodeURIComponent( prompt( i18n.text("IndexCommand.TextToAnalyze") ) ), function(r) {
98                                 alert(JSON.stringify(r, true, "  "));
99                         });
100                 },
101                 _deleteIndexAction_handler: function(index) {
102                         if( prompt( i18n.text("AliasForm.DeleteAliasMessage", i18n.text("Command.DELETE"), index.name ) ) === i18n.text("Command.DELETE") ) {
103                                 this.cluster["delete"](encodeURIComponent( index.name ), null, function(r) {
104                                         alert(JSON.stringify(r));
105                                         this.fire("redraw");
106                                 }.bind(this) );
107                         }
108                 },
109                 _shutdownNode_handler: function(node) {
110                         if(prompt( i18n.text("IndexCommand.ShutdownMessage", i18n.text("Command.SHUTDOWN"), node.cluster.name ) ) === i18n.text("Command.SHUTDOWN") ) {
111                                 this.cluster.post( "_cluster/nodes/" + encodeURIComponent( node.name ) + "/_shutdown", null, function(r) {
112                                         alert(JSON.stringify(r));
113                                         this.fire("redraw");
114                                 }.bind(this));
115                         }
116                 },
117                 _deleteAliasAction_handler: function( index, alias ) {
118                         if( confirm( i18n.text("Command.DeleteAliasMessage" ) ) ) {
119                                 var command = {
120                                         "actions" : [
121                                                 { "remove" : { "index" : index.name, "alias" : alias.name } }
122                                         ]
123                                 };
124                                 this.config.cluster.post('_aliases', JSON.stringify(command), function(d) {
125                                         alert(JSON.stringify(d));
126                                         this.fire("redraw");
127                                 }.bind(this) );
128                         }
129                 },
130
131                 _replica_template: function(replica) {
132                         var r = replica.replica;
133                         return { tag: "DIV",
134                                 cls: "uiNodesView-replica" + (r.primary ? " primary" : "") + ( " state-" + r.state ),
135                                 text: r.shard.toString(),
136                                 onclick: function() { new ui.JsonPanel({
137                                         json: replica.status || r,
138                                         title: r.index + "/" + r.node + " [" + r.shard + "]" });
139                                 }
140                         };
141                 },
142                 _routing_template: function(routing) {
143                         var cell = { tag: "TD", cls: "uiNodesView-routing" + (routing.open ? "" : " close"), children: [] };
144                         for(var i = 0; i < routing.replicas.length; i++) {
145                                 if(i % routing.max_number_of_shards === 0 && i > 0) {
146                                         cell.children.push({ tag: "BR" });
147                                 }
148                                 if( routing.replicas[i] ) {
149                                         cell.children.push(this._replica_template(routing.replicas[i]));
150                                 } else {
151                                         cell.children.push( { tag: "DIV", cls: "uiNodesView-nullReplica" } );
152                                 }
153                         }
154                         return cell;
155                 },
156                 _nodeControls_template: function( node ) { return (
157                         { tag: "DIV", cls: "uiNodesView-controls", children: [
158                                 new ui.MenuButton({
159                                         label: i18n.text("NodeInfoMenu.Title"),
160                                         menu: new ui.MenuPanel({
161                                                 items: [
162                                                         { text: i18n.text("NodeInfoMenu.ClusterNodeInfo"), onclick: function() { new ui.JsonPanel({ json: node.cluster, title: node.name });} },
163                                                         { text: i18n.text("NodeInfoMenu.NodeStats"), onclick: function() { new ui.JsonPanel({ json: node.stats, title: node.name });} }
164                                                 ]
165                                         })
166                                 }),
167                                 new ui.MenuButton({
168                                         label: i18n.text("NodeActionsMenu.Title"),
169                                         menu: new ui.MenuPanel({
170                                                 items: [
171                                                         { text: i18n.text("NodeActionsMenu.Shutdown"), onclick: function() { this._shutdownNode_handler(node); }.bind(this) }
172                                                 ]
173                                         })
174                                 })
175                         ] }
176                 ); },
177                 _nodeIcon_template: function( node ) {
178                         var icon, alt;
179                         if( node.name === "Unassigned" ) {
180                                 icon = "fa-exclamation-triangle";
181                                 alt = i18n.text( "NodeType.Unassigned" );
182                         } else if( node.cluster.settings && "tribe" in node.cluster.settings) {
183                                 icon = "fa-sitemap";
184                                 alt = i18n.text("NodeType.Tribe" );
185                         } else {
186                                 icon = "fa-" + (node.master_node ? "star" : "circle") + (node.data_node ? "" : "-o" );
187                                 alt = i18n.text( node.master_node ? ( node.data_node ? "NodeType.Master" : "NodeType.Coord" ) : ( node.data_node ? "NodeType.Worker" : "NodeType.Client" ) );
188                         }
189                         return { tag: "TD", title: alt, cls: "uiNodesView-icon", children: [
190                                 { tag: "SPAN", cls: "fa fa-2x " + icon }
191                         ] };
192                 },
193                 _node_template: function(node) {
194                         return { tag: "TR", cls: "uiNodesView-node" + (node.master_node ? " master": ""), children: [
195                                 this._nodeIcon_template( node ),
196                                 { tag: "TH", children: node.name === "Unassigned" ? [
197                                         { tag: "H3", text: node.name }
198                                 ] : [
199                                         { tag: "H3", text: node.cluster.name },
200                                         { tag: "DIV", text: node.cluster.hostname },
201                                         this.interactive ? this._nodeControls_template( node ) : null
202                                 ] }
203                         ].concat(node.routings.map(this._routing_template, this))};
204                 },
205                 _indexHeaderControls_template: function( index ) { return (
206                         { tag: "DIV", cls: "uiNodesView-controls", children: [
207                                 new ui.MenuButton({
208                                         label: i18n.text("IndexInfoMenu.Title"),
209                                         menu: new ui.MenuPanel({
210                                                 items: [
211                                                         { text: i18n.text("IndexInfoMenu.Status"), onclick: function() { new ui.JsonPanel({ json: index.status, title: index.name }); } },
212                                                         { text: i18n.text("IndexInfoMenu.Metadata"), onclick: function() { new ui.JsonPanel({ json: index.metadata, title: index.name }); } }
213                                                 ]
214                                         })
215                                 }),
216                                 new ui.MenuButton({
217                                         label: i18n.text("IndexActionsMenu.Title"),
218                                         menu: new ui.MenuPanel({
219                                                 items: [
220                                                         { text: i18n.text("IndexActionsMenu.NewAlias"), onclick: function() { this._newAliasAction_handler(index); }.bind(this) },
221                                                         { text: i18n.text("IndexActionsMenu.Refresh"), onclick: function() { this._postIndexAction_handler("_refresh", index, false); }.bind(this) },
222                                                         { text: i18n.text("IndexActionsMenu.Flush"), onclick: function() { this._postIndexAction_handler("_flush", index, false); }.bind(this) },
223                                                         { text: i18n.text("IndexActionsMenu.Optimize"), onclick: function () { this._optimizeIndex_handler(index); }.bind(this) },
224                                                         { text: i18n.text("IndexActionsMenu.Snapshot"), disabled: closed, onclick: function() { this._postIndexAction_handler("_gateway/snapshot", index, false); }.bind(this) },
225                                                         { text: i18n.text("IndexActionsMenu.Analyser"), onclick: function() { this._testAnalyser_handler(index); }.bind(this) },
226                                                         { text: (index.state === "close") ? i18n.text("IndexActionsMenu.Open") : i18n.text("IndexActionsMenu.Close"), onclick: function() { this._postIndexAction_handler((index.state === "close") ? "_open" : "_close", index, true); }.bind(this) },
227                                                         { text: i18n.text("IndexActionsMenu.Delete"), onclick: function() { this._deleteIndexAction_handler(index); }.bind(this) }
228                                                 ]
229                                         })
230                                 })
231                         ] }
232                 ); },
233                 _indexHeader_template: function( index ) {
234                         var closed = index.state === "close";
235                         var line1 = closed ? "index: close" : ( "size: " + (index.status && index.status.primaries && index.status.total ? ut.byteSize_template( index.status.primaries.store.size_in_bytes ) + " (" + ut.byteSize_template( index.status.total.store.size_in_bytes ) + ")" : "unknown" ) );
236                         var line2 = closed ? "\u00A0" : ( "docs: " + (index.status && index.status.primaries && index.status.primaries.docs && index.status.total && index.status.total.docs ? index.status.primaries.docs.count.toLocaleString() + " (" + (index.status.total.docs.count + index.status.total.docs.deleted).toLocaleString() + ")" : "unknown" ) );
237                         return index.name ? { tag: "TH", cls: (closed ? "close" : ""), children: [
238                                 { tag: "H3", text: index.name },
239                                 { tag: "DIV", text: line1 },
240                                 { tag: "DIV", text: line2 },
241                                 this.interactive ? this._indexHeaderControls_template( index ) : null
242                         ] } : [ { tag: "TD" }, { tag: "TH" } ];
243                 },
244                 _aliasRender_template_none: function( cluster, indices ) {
245                         return null;
246                 },
247                 _aliasRender_template_list: function( cluster, indices ) {
248                         return cluster.aliases.length && { tag: "TBODY", children: [
249                                 { tag: "TR", children: [
250                                         { tag: "TD" }
251                                 ].concat( indices.map( function( index ) {
252                                         return { tag: "TD", children: index.metadata && index.metadata.aliases.map( function( alias ) {
253                                                 return { tag: "LI", text: alias };
254                                         } ) };
255                                 })) }
256                         ] };
257                 },
258                 _aliasRender_template_full: function( cluster, indices ) {
259                         return cluster.aliases.length && { tag: "TBODY", children: cluster.aliases.map( function(alias, row) {
260                                 return { tag: "TR", children: [ { tag: "TD" },{ tag: "TD" } ].concat(alias.indices.map(function(index, i) {
261                                         if (index) {
262                                                 return {
263                                                         tag: "TD",
264                                                         css: { background: "#" + "9ce9c7fc9".substr((row+6)%7,3) },
265                                                         cls: "uiNodesView-hasAlias" + ( alias.min === i ? " min" : "" ) + ( alias.max === i ? " max" : "" ),
266                                                         text: alias.name,
267                                                         children: this.interactive ? [
268                                                                 {       tag: 'SPAN',
269                                                                         text: i18n.text("General.CloseGlyph"),
270                                                                         cls: 'uiNodesView-hasAlias-remove',
271                                                                         onclick: this._deleteAliasAction_handler.bind( this, index, alias )
272                                                                 }
273                                                         ]: null
274                                                 };
275                                         }       else {
276                                                 return { tag: "TD" };
277                                         }
278                                 }, this ) ) };
279                         }, this )       };
280                 },
281                 _main_template: function(cluster, indices) {
282                         return { tag: "TABLE", cls: "table uiNodesView", children: [
283                                 this._styleSheetEl,
284                                 { tag: "THEAD", children: [ { tag: "TR", children: indices.map(this._indexHeader_template, this) } ] },
285                                 this._aliasRenderFunction( cluster, indices ),
286                                 { tag: "TBODY", children: cluster.nodes.map(this._node_template, this) }
287                         ] };
288                 }
289
290         });
291
292 })( this.app, this.i18n, this.joey );