diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java index 0b24151d7186f8cde568e6534b2f04b7bf94b8a1..0ea760c5443687d23d77008224153b5dd95797da 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java @@ -11,10 +11,17 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.bson.types.ObjectId; + import de.vipra.rest.model.Wrapper; import de.vipra.util.BuildInfo; +import de.vipra.util.Config; import de.vipra.util.NestedMap; import de.vipra.util.StringUtils; +import de.vipra.util.model.Article; +import de.vipra.util.model.Topic; +import de.vipra.util.model.Word; +import de.vipra.util.service.MongoService; @Path("info") public class InfoResource { @@ -22,13 +29,20 @@ public class InfoResource { @Context UriInfo uri; - private static final NestedMap info = new NestedMap(); + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getInfo() { + Wrapper<NestedMap> res = new Wrapper<>(); + NestedMap info = new NestedMap(); - static { try { RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); Runtime rt = Runtime.getRuntime(); BuildInfo buildInfo = new BuildInfo(); + Config config = Config.getConfig(); + MongoService<Article, ObjectId> dbArticles = MongoService.getDatabaseService(config, Article.class); + MongoService<Topic, ObjectId> dbTopics = MongoService.getDatabaseService(config, Topic.class); + MongoService<Word, String> dbWords = MongoService.getDatabaseService(config, Word.class); // vm info info.put("vm.starttime", rb.getStartTime()); @@ -48,15 +62,15 @@ public class InfoResource { info.put("app.gitsha1", buildInfo.getGitSHA1()); info.put("app.version", buildInfo.getVersion()); info.put("app.builddate", buildInfo.getBuildDate()); + + // database info + info.put("db.articles", dbArticles.count()); + info.put("db.topics", dbTopics.count()); + info.put("db.words", dbWords.count()); } catch (Exception e) { info.put("error", e.getMessage()); } - } - @GET - @Produces(MediaType.APPLICATION_JSON) - public Response getInfo() { - Wrapper<NestedMap> res = new Wrapper<>(); return res.ok(info); } } diff --git a/vipra-ui/app/html/about.html b/vipra-ui/app/html/about.html new file mode 100644 index 0000000000000000000000000000000000000000..2f363e4a0c6f85a526ad52b6f9ed9f20529fbcec --- /dev/null +++ b/vipra-ui/app/html/about.html @@ -0,0 +1,101 @@ +<div ui-view ng-cloak> + <div class="page-header"> + <h1>About</h1> + </div> + + <p><strong>Vipra</strong></p> + + <p>Created by Eike Cochu</p> + + <h3>Description</h3> + + <p>The Vipra application is a topic modeling based search system with a frontend web application, a backend REST service and a maintenance tool for data import and modeling. It attempts to leverage automatically discovered topic informations in document collections to ease collection browsing and organization. The search system relies on ElasticSearch and Apache Lucene.</p> + + <p>This application was created by Eike Cochu for his master's degree thesis in computer science, 2015-2016 at the Freie Universität in Berlin, Germany.</p> + + <h3>License</h3> + + <p>The MIT License (MIT)</p> + + <p>Copyright 2016 Eike Cochu</p> + + <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p> + + <p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p> + + <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p> + + <hr> + + <h3>Version</h3> + + <table class="table table-bordered table-fixed"> + <tbody> + <tr> + <th style="width:33%">Git Version</th> + <td ng-bind="::info.app.gitsha1"></td> + </tr> + <tr> + <th>Artifact Version</th> + <td ng-bind="::info.app.version"></td> + </tr> + <tr> + <th>Build date</th> + <td ng-bind="::buildDate"></td> + </tr> + </tbody> + </table> + + <h3>Host</h3> + + <table class="table table-bordered table-fixed"> + <tbody> + <tr> + <th style="width:33%">CPU Cores</th> + <td ng-bind="::info.host.cores"></td> + </tr> + <tr> + <th>Available memory</th> + <td ng-bind="::info.host.memory"></td> + </tr> + <tr> + <th>OS</th> + <td ng-bind-template="{{::info.host.os.name}} ({{::info.host.os.arch}}) {{::info.host.os.version}}"></td> + </tr> + </tbody> + </table> + + <h3>VM</h3> + + <table class="table table-bordered table-fixed"> + <tbody> + <tr> + <th style="width:33%">Java</th> + <td ng-bind-template="{{::info.vm.java.vendor}} {{::info.vm.java.version}}"></td> + </tr> + <tr> + <th>Start time</th> + <td ng-bind-template="{{::startTime}} (up {{::upTime}})"></td> + </tr> + </tbody> + </table> + + <h3>Database</h3> + + <table class="table table-bordered table-fixed"> + <tbody> + <tr> + <th style="width:33%"># of articles</th> + <td ng-bind-template="{{::info.db.articles}}"></td> + </tr> + <tr> + <th># of topics</th> + <td ng-bind-template="{{::info.db.topics}}"></td> + </tr> + <tr> + <th># of words</th> + <td ng-bind-template="{{::info.db.words}}"></td> + </tr> + </tbody> + </table> +</div> \ No newline at end of file diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html index ddbbc3798f05fc2961eeee119d1fa2949654a426..c13bd0d49afcf71e23a482e41d54e28329aef4f7 100644 --- a/vipra-ui/app/index.html +++ b/vipra-ui/app/index.html @@ -55,6 +55,14 @@ <li ng-class="{active:$state.includes('topics')}"><a ui-sref="topics">Topics</a></li> <li ng-class="{active:$state.includes('words')}"><a ui-sref="words">Words</a></li> </ul> + + <ul class="nav navbar-nav navbar-right"> + <li ng-class="{active:$state.includes('about')}"> + <a ui-sref="about"> + <span class="glyphicon glyphicon-question-sign"></span> + </a> + </li> + </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index d44403e71662ce72062bd7f3489e5cbc8e28c345..ec274b7df27d80135b16ae32ceaa85e19e092831 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -28,6 +28,12 @@ controller: 'IndexController' }); + $stateProvider.state('about', { + url: '/about', + templateUrl: Vipra.const.tplBase + '/about.html', + controller: 'AboutController' + }); + $stateProvider.state('network', { url: '/network/:type/:id', templateUrl: Vipra.const.tplBase + '/network.html', diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 49ac6552309c2f3389ce550caa7e4caf45918b86..739050f1a441182731fc0a676bb83f8fb5bfa5b5 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -50,6 +50,21 @@ }]); + /** + * About controller + */ + app.controller('AboutController', ['$scope', 'InfoFactory', + function($scope, InfoFactory) { + + InfoFactory.get(function(response) { + $scope.info = response.data; + $scope.buildDate = Vipra.formatDateTime(moment($scope.info.app.builddate, 'YYMMDD_HHmm').toDate()); + $scope.startTime = Vipra.formatDateTime(moment($scope.info.vm.starttime, 'x').toDate()); + $scope.upTime = moment.duration($scope.info.vm.uptime).humanize(); + }); + + }]); + /** * Network controller */ diff --git a/vipra-ui/app/js/factories.js b/vipra-ui/app/js/factories.js index 9224eb92350d82deec477ead6cc79143a5f82106..b6f203282cd302538815b4920e0740dd4790222f 100644 --- a/vipra-ui/app/js/factories.js +++ b/vipra-ui/app/js/factories.js @@ -33,6 +33,10 @@ }); }]); + app.factory('InfoFactory', ['$resource', function($resource) { + return $resource(Vipra.config.restUrl + '/info'); + }]); + // https://gist.github.com/Fluidbyte/4718380 app.factory('Store', ['$state', function($state) { return function(key, value) { diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index 613e9dcae846fe655a746e9915f267c0310aeb8c..e046f3391ec69c1f1338a5ffdb31fff783de685d 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -216,6 +216,10 @@ ul.dashed { min-height: 48px; } +.table-fixed { + table-layout: fixed; +} + [sort-by] { .noselect; cursor: pointer; diff --git a/vipra-ui/bower.json b/vipra-ui/bower.json index 867ff59995c6ed82bfdfd58bb5ac40a1f054e650..53906a9c0f53189a6b885080bfbfcd1cd076d157 100644 --- a/vipra-ui/bower.json +++ b/vipra-ui/bower.json @@ -26,6 +26,7 @@ "highcharts": "^4.2.2", "nprogress": "^0.2.0", "vis": "https://github.com/almende/vis.git#^4.14.0", - "angular-websocket": "^1.0.14" + "angular-websocket": "^1.0.14", + "moment": "^2.11.2" } } diff --git a/vipra-ui/gulpfile.js b/vipra-ui/gulpfile.js index c694b87ecf4986f3802eca94f038ccc823d1815e..0ab4b7f617f0330b05e96b4584ed66ee5fdd6083 100644 --- a/vipra-ui/gulpfile.js +++ b/vipra-ui/gulpfile.js @@ -18,7 +18,8 @@ var assets = { 'bower_components/bootstrap/dist/js/bootstrap.min.js', 'bower_components/highcharts/highcharts.js', 'bower_components/vis/dist/vis.min.js', - 'bower_components/nprogress/nprogress.js' + 'bower_components/nprogress/nprogress.js', + 'bower_components/moment/min/moment.min.js' ], css: [ 'bower_components/bootstrap/dist/css/bootstrap.min.css',