Skip to content

Commit

Permalink
Resolves #487 - Create a hawtio ElasticSearch plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
cmoulliard committed Aug 23, 2013
1 parent a0b658f commit a9d8b6a
Show file tree
Hide file tree
Showing 12 changed files with 22,755 additions and 1 deletion.
2 changes: 1 addition & 1 deletion hawtio-plugin-examples/simple-plugin/pom.xml
Expand Up @@ -18,7 +18,7 @@
<plugin-context>/hawtio/simple-plugin</plugin-context>
<plugin-name>${project.artifactId}</plugin-name>
<plugin-domain />
<plugin-scripts>app/js/simplePlugin.js</plugin-scripts>
<plugin-scripts>app/js/simplePlugin.ts</plugin-scripts>

<fuse.osgi.import>
*;resolution:=optional
Expand Down
3 changes: 3 additions & 0 deletions hawtio-web/src/main/webapp/app/elasticsearch/doc/help.md
@@ -0,0 +1,3 @@
### Elasticsearch

TODO.
160 changes: 160 additions & 0 deletions hawtio-web/src/main/webapp/app/elasticsearch/html/es.html
@@ -0,0 +1,160 @@
<div ng-controller="ES.SearchCtrl">
<div class="">
<div class="">
<div class="container-fluid">
<span class="brand">Elastic.js Angular Example</span>
<button ng-click="indexSampleDocs()" class="btn btn-inverse pull-right">Index Sample Docs</button>
</div>
<br/>
<!--<a href="#/search"> <i class="icon-search"></i> Return to Search</a>-->
<div class="row-fluid">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="defaultEsServer" title="Default ES Server">ES Server</label>

<div class="controls">
<input id="defaultEsServer" name="defaultEsServer" type="text" ng-model="defaultEsServer"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="QueryTerm" title="Enter a term to query. Could be *">Query Term</label>

<div class="controls">
<input id="QueryTerm" name="QueryTerm" type="text" ng-model="queryTerm"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="indice" title="Enter an index. By example - 'twitter'">Indice to be searched</label>

<div class="controls">
<input id="indice" name="indice" type="text" ng-model="indice"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="docType" title="Enter a document type. By example - 'tweet'">Document Type</label>

<div class="controls">
<input id="docType" name="docType" type="text" ng-model="docType"/>
</div>
</div>
<div class="control-group">
<div class="controls">
<input type="submit" value="ES Search" class="btn" ng-click="search()"/>
</div>
</div>
</form>
</div>
</div>
<div class="row-fluid">
<div>
Documents Found : {{results.hits.total}}
<!--<a ng-ref="/search"> <i class="icon-search"></i> Return to Search</a>-->
<table class="table table-striped table-hover">
<thead>
<tr>
<th>User</th>
<th>Posted Date</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="doc in results.hits.hits">
<td>{{doc._source.user}}</td>
<td>{{doc._source.postedDate}}</td>
<td>{{doc._source.message}}</td>
</tr>
</tbody>
</table>
</div>
</div>

<!-- Error Panel -->
<div class="row-fluid">
<div class="span12 alert alert-error panel-error" ng-hide="!panel.error">
<a class="close" ng-click="panel.error=false">&times;</a>
<i class="icon-exclamation-sign"></i> <strong>Oops!</strong> {{panel.error}}
</div>
</div>

<!--
<div>
<div ng-controller='histogram' ng-init="init()" style="height:4">
<style>
.histogram-legend {
display: inline-block;
padding-right: 5px
}
.histogram-legend-dot {
display: inline-block;
height: 10px;
width: 10px;
border-radius: 5px;
}
.histogram-legend-item {
display: inline-block;
}
.histogram-chart {
position: relative;
}
</style>
<span ng-show="panel.spyable" class='spy panelextra pointer'>
<i bs-modal="'partials/inspector.html'" class="icon-eye-open"></i>
</span>
<div>
<span ng-show='panel.zoomlinks && data'>
<a class='small' ng-click='zoom(0.5)'><i class='icon-zoom-in'></i> Zoom In</a>
<a class='small' ng-click='zoom(2)'><i class='icon-zoom-out'></i> Zoom Out</a> |
</span>
<span ng-show="panel.legend" ng-repeat='series in data' class="histogram-legend">
<i class='icon-circle' ng-style="{color: series.info.color}"></i>
<span class='small histogram-legend-item'>{{series.info.alias}} ({{series.hits}})</span>
</span>
<span ng-show="panel.legend" class="small"><span ng-show="panel.value_field && panel.mode != 'count'">{{panel.value_field}}</span> {{panel.mode}} per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> hits)</span>
</div>
<center><img ng-show='panel.loading && _.isUndefined(data)' src="common/img/load_big.gif"></center>
<div histogram-chart class="histogram-chart" params="{{panel}}"></div>
</div>
</div>
-->
</div>

<!--
<div class="row-fluid">
<form class="span4 offset4 form-inline" ng-submit="search()">
<input class="input-xlarge" ng-model="queryTerm" type="text"
placeholder="Enter a keyword" autofocus>
<button class="btn" type="submit">Search</button>
</form>
</div>
<div class="row-fluid" style="margin-top:10%">
<div class="span4 offset4">
<span class="span5">Found {{results.hits.total}} Results</span></span>
<span class="span5 offset2">
<a href="#/search"> <i class="icon-search"></i> Return to Search</a>
</span>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>User</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="doc in results.hits.hits">
<td>{{doc._source.user}}</td>
<td>{{doc._source.message}}</td>
</tr>
</tbody>
</table>
</div>
</div>
-->
</div>
10 changes: 10 additions & 0 deletions hawtio-web/src/main/webapp/app/elasticsearch/js/config.ts
@@ -0,0 +1,10 @@
module ES {

export var config = {
elasticsearch: "http://" + window.location.hostname + ":9200",
indice: "twitter",
doctype: "tweet",
query: "*"
};

}
33 changes: 33 additions & 0 deletions hawtio-web/src/main/webapp/app/elasticsearch/js/esPlugin.ts
@@ -0,0 +1,33 @@
module ES {

var pluginEsName = 'elasticjs';
var base_url = 'app/elasticsearch/html';

/* Application level module which depends on filters, controllers, and services */
angular.module(pluginEsName, ['bootstrap','ngResource','elasticjs.service'])

.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/search', {templateUrl: base_url + '/search.html'})
.when('/results', {templateUrl: base_url + '/results.html'})
.when('/elasticjs', {templateUrl: base_url + '/es.html'})
}])

.run(($location:ng.ILocationService, workspace:Workspace, viewRegistry, layoutFull) => {

// Use Full Layout of Hawtio
viewRegistry['elasticjs'] = 'app/elasticsearch/html/es.html';

// Set up top-level link to our plugin
workspace.topLevelTabs.push({
content: "ElasticJs",
title: "ElasticJs plugin loaded dynamically",
isValid: (workspace) => true,
href: () => '#/elasticjs',
isActive: (workspace:Workspace) => workspace.isLinkActive("elasticjs")
});

});

hawtioPluginLoader.addModule(pluginEsName);
}
166 changes: 166 additions & 0 deletions hawtio-web/src/main/webapp/app/elasticsearch/js/helpers.ts
@@ -0,0 +1,166 @@
module ES {

// Function to test if a property is empty, not null
export function isEmptyObject(value) {
return $.isEmptyObject(value);
}


// Search Angular Controller used by ES
export function SearchCtrl($scope, $location, $log, ejsResource) {

// Retrieve by default parameters from config.js
//var defaultEsServer = $scope.defaultEsServer = "http://localhost:9200";
var defaultEsServer = $scope.defaultEsServer = config["elasticsearch"];
var query = $scope.queryTerm = config["query"];
var index = $scope.indice = config["indice"];
var type = $scope.docType = config["doctype"];
var ejs = ejsResource(defaultEsServer);
$scope.log = $log;

// setup the indices and types to search across
var request;

$scope.parse_error = function(data) {
var _error = data.match("nested: (.*?);");
return _error == null ? data : _error[1];
};

// define our search function that will be called when a user
// submits a search
$scope.search = function () {

console.log("Search button called");
console.log("ES Server = " + $scope.defaultEsServer);
console.log("Indice value = " + $scope.indice);
console.log("Indice = " + index);
console.log("Type value = " + $scope.docType);
console.log("Type = " + type);

if (!isEmptyObject($scope.indice)) {
index = $scope.indice;
} else {
index = 'twitter';
}

if (!isEmptyObject($scope.docType)) {
type = $scope.docType;
} else {
type = 'tweet';
}

// Call ES server
var ejs = ejsResource($scope.defaultEsServer);

// Define Request to call ES
var request = ejs.Request()
.indices(index)
.types(type);

// Setup query
request = request
.query(ejs.QueryStringQuery(query));

// Run query
var results = request.doSearch();

results.then(function(results) {

//$location.path("/elasticjs");

// Reset fields after search
$scope.queryTerm = "";
$scope.indice = "";
$scope.docType = "";

if (typeof results.error != 'undefined') {

// Message should be displayed in the web page as a modal window
console.error("Cannot connect to the ES Server");

// Solution proposed by kibana3
// $scope.panel.error = $scope.parse_error(results.error);
return;
}

console.log( results.length + " : results retrieved");
$scope.results = results;

});

};

// index the sample documents
$scope.indexSampleDocs = function () {

// our example documents
var docs = [
ejs.Document(index, type, '1').source({
user: 'mrweber',
postedDate: '2013-08-22T18:30:00',
message: 'Elastic.js - a Javascript implementation of the ElasticSearch Query DSL and Core API'}),

ejs.Document(index, type, '2').source({
user: 'egaumer',
postedDate: '2013-08-22T18:25:00',
message: 'FullScale Labs just released Elastic.js go check it out!'
}),

ejs.Document(index, type, '3').source({
user: 'dataintensive',
postedDate: '2013-08-22T18:10:00',
message: 'We are pleased to announce Elastic.js an implementation of the #elasticsearch query dsl'
}),

ejs.Document(index, type, '4').source({
user: 'kimchy',
postedDate: '2013-08-22T18:10:00',
message: 'The FullScale Labs team are awesome! Go check out Elastic.js'
}),

ejs.Document(index, type, '5').source({
user: 'egaumer',
postedDate: '2013-08-22T18:05:00',
message: 'Use elastic.js to write a complex query and translate it to json with our query translator'
}),

ejs.Document(index, type, '6').source({
user: 'cmoulliard',
postedDate: '2013-08-22T18:30:00',
message: 'Elastic.js - a Javascript implementation of the ElasticSearch Query DSL and Core API'}),

ejs.Document(index, type, '7').source({
user: 'cmoulliard',
postedDate: '2013-08-22T18:25:00',
message: 'FullScale Labs just released Elastic.js go check it out!'
}),

ejs.Document(index, type, '8').source({
user: 'jstrachan',
postedDate: '2013-08-22T18:10:00',
message: 'We are pleased to announce Elastic.js an implementation of the #elasticsearch query dsl'
}),

ejs.Document(index, type, '9').source({
user: 'davclaus',
postedDate: '2013-08-22T18:10:00',
message: 'The FullScale Labs team are awesome! Go check out Elastic.js'
}),

ejs.Document(index, type, '10').source({
user: 'egaumer',
postedDate: '2013-08-22T18:05:00',
message: 'Use elastic.js to write a complex query and translate it to json with our query translator'
})
];

// Using sugarjs & ECMA5 forEach
var doSearch = ( $scope.search ).after(docs.length);
docs.forEach(function (doc) {
doc.refresh(true).doIndex(doSearch);
});

};

};
}
3 changes: 3 additions & 0 deletions hawtio-web/src/main/webapp/app/elasticsearch/js/histogram.ts
@@ -0,0 +1,3 @@
module ES {

}

0 comments on commit a9d8b6a

Please sign in to comment.