svn commit: r1776930 [2/19] - in /ofbiz/trunk/specialpurpose: lucene/ lucene/src/main/java/org/apache/ofbiz/content/search/ solr/ solr/src/main/java/org/apache/ofbiz/solr/webapp/ solr/webapp/solr/ solr/webapp/solr/WEB-INF/ solr/webapp/solr/css/ solr/we...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1776930 [2/19] - in /ofbiz/trunk/specialpurpose: lucene/ lucene/src/main/java/org/apache/ofbiz/content/search/ solr/ solr/src/main/java/org/apache/ofbiz/solr/webapp/ solr/webapp/solr/ solr/webapp/solr/WEB-INF/ solr/webapp/solr/css/ solr/we...

shijh
Added: ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/app.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/app.js?rev=1776930&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/app.js (added)
+++ ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/app.js Mon Jan  2 13:44:06 2017
@@ -0,0 +1,799 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+var solrAdminApp = angular.module("solrAdminApp", [
+  "ngResource",
+  "ngRoute",
+  "ngCookies",
+  "ngtimeago",
+  "solrAdminServices",
+  "localytics.directives"
+]);
+
+solrAdminApp.config([
+  '$routeProvider', function($routeProvider) {
+    $routeProvider.
+      when('/', {
+        templateUrl: 'partials/index.html',
+        controller: 'IndexController'
+      }).
+      when('/~logging', {
+        templateUrl: 'partials/logging.html',
+        controller: 'LoggingController'
+      }).
+      when('/~logging/level', {
+        templateUrl: 'partials/logging-levels.html',
+        controller: 'LoggingLevelController'
+      }).
+      when('/~cloud', {
+        templateUrl: 'partials/cloud.html',
+        controller: 'CloudController'
+      }).
+      when('/~cores', {
+        templateUrl: 'partials/cores.html',
+        controller: 'CoreAdminController'
+      }).
+      when('/~cores/:corename', {
+        templateUrl: 'partials/cores.html',
+        controller: 'CoreAdminController'
+      }).
+      when('/~collections', {
+        templateUrl: 'partials/collections.html',
+        controller: 'CollectionsController'
+      }).
+      when('/~collections/:collection', {
+        templateUrl: 'partials/collections.html',
+        controller: 'CollectionsController'
+      }).
+      when('/~threads', {
+        templateUrl: 'partials/threads.html',
+        controller: 'ThreadsController'
+      }).
+      when('/~java-properties', {
+        templateUrl: 'partials/java-properties.html',
+        controller: 'JavaPropertiesController'
+      }).
+      when('/:core', {
+        templateUrl: 'partials/core_overview.html',
+        controller: 'CoreOverviewController'
+      }).
+      when('/:core/collection-overview', {
+        templateUrl: 'partials/collection_overview.html',
+        controller: 'CollectionOverviewController'
+      }).
+      when('/:core/analysis', {
+        templateUrl: 'partials/analysis.html',
+        controller: 'AnalysisController'
+      }).
+      when('/:core/dataimport', {
+        templateUrl: 'partials/dataimport.html',
+        controller: 'DataImportController'
+      }).
+      when('/:core/dataimport/:handler*', {
+        templateUrl: 'partials/dataimport.html',
+        controller: 'DataImportController'
+      }).
+      when('/:core/documents', {
+        templateUrl: 'partials/documents.html',
+        controller: 'DocumentsController'
+      }).
+      when('/:core/files', {
+        templateUrl: 'partials/files.html',
+        controller: 'FilesController'
+      }).
+      when('/:core/plugins', {
+        templateUrl: 'partials/plugins.html',
+        controller: 'PluginsController',
+        reloadOnSearch: false
+      }).
+      when('/:core/plugins/:legacytype', {
+        templateUrl: 'partials/plugins.html',
+        controller: 'PluginsController',
+        reloadOnSearch: false
+      }).
+      when('/:core/query', {
+        templateUrl: 'partials/query.html',
+        controller: 'QueryController'
+      }).
+      when('/:core/stream', {
+        templateUrl: 'partials/stream.html',
+        controller: 'StreamController'
+      }).
+      when('/:core/replication', {
+        templateUrl: 'partials/replication.html',
+        controller: 'ReplicationController'
+      }).
+      when('/:core/dataimport', {
+        templateUrl: 'partials/dataimport.html',
+        controller: 'DataImportController'
+      }).
+      when('/:core/dataimport/:handler*', {
+        templateUrl: 'partials/dataimport.html',
+        controller: 'DataImportController'
+      }).
+      when('/:core/schema', {
+        templateUrl: 'partials/schema.html',
+        controller: 'SchemaController'
+      }).
+      when('/:core/segments', {
+        templateUrl: 'partials/segments.html',
+        controller: 'SegmentsController'
+      }).
+      otherwise({
+        redirectTo: '/'
+      });
+}])
+.constant('Constants', {
+  IS_ROOT_PAGE: 1,
+  IS_CORE_PAGE: 2,
+  IS_COLLECTION_PAGE: 3,
+  ROOT_URL: "/"
+})
+.filter('uriencode', function() {
+  return window.encodeURIComponent;
+})
+.filter('highlight', function($sce) {
+  return function(input, lang) {
+    if (lang && input && lang!="txt") return hljs.highlight(lang, input).value;
+    return input;
+  }
+})
+.filter('unsafe', function($sce) { return $sce.trustAsHtml; })
+.directive('loadingStatusMessage', function() {
+  return {
+    link: function($scope, $element, attrs) {
+      var show = function() {$element.css('display', 'block')};
+      var hide = function() {$element.css('display', 'none')};
+      $scope.$on('loadingStatusActive', show);
+      $scope.$on('loadingStatusInactive', hide);
+    }
+  };
+})
+.directive('escapePressed', function () {
+    return function (scope, element, attrs) {
+        element.bind("keydown keypress", function (event) {
+            if(event.which === 27) {
+                scope.$apply(function (){
+                    scope.$eval(attrs.escapePressed);
+                });
+                event.preventDefault();
+            }
+        });
+    };
+})
+.directive('focusWhen', function($timeout) {
+  return {
+    link: function(scope, element, attrs) {
+      scope.$watch(attrs.focusWhen, function(value) {
+        if(value === true) {
+          $timeout(function() {
+            element[0].focus();
+          }, 100);
+        }
+      });
+    }
+  };
+})
+.directive('scrollableWhenSmall', function($window) {
+  return {
+    link: function(scope, element, attrs) {
+      var w = angular.element($window);
+
+      var checkFixedMenu = function() {
+        var shouldScroll = w.height() < (element.height() + $('#header').height() + 40);
+        element.toggleClass( 'scroll', shouldScroll);
+      };
+      w.bind('resize', checkFixedMenu);
+      w.bind('load', checkFixedMenu);
+    }
+  }
+})
+.filter('readableSeconds', function() {
+    return function(input) {
+    seconds = parseInt(input||0, 10);
+    var minutes = Math.floor( seconds / 60 );
+    var hours = Math.floor( minutes / 60 );
+
+    var text = [];
+    if( 0 !== hours ) {
+      text.push( hours + 'h' );
+      seconds -= hours * 60 * 60;
+      minutes -= hours * 60;
+    }
+
+    if( 0 !== minutes ) {
+      text.push( minutes + 'm' );
+      seconds -= minutes * 60;
+    }
+
+    if( 0 !== seconds ) {
+      text.push( ( '0' + seconds ).substr( -2 ) + 's' );
+    }
+    return text.join(' ');
+  };
+})
+.filter('number', function($locale) {
+    return function(input) {
+        var sep = {
+          'de_CH' : '\'',
+          'de' : '.',
+          'en' : ',',
+          'es' : '.',
+          'it' : '.',
+          'ja' : ',',
+          'sv' : ' ',
+          'tr' : '.',
+          '_' : '' // fallback
+        };
+
+        var browser = {};
+        var match = $locale.id.match( /^(\w{2})([-_](\w{2}))?$/ );
+        if (match[1]) {
+            browser.language = match[1].toLowerCase();
+        }
+        if (match[1] && match[3]) {
+            browser.locale = match[1] + '_' + match[3];
+        }
+
+        return ( input || 0 ).toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+            sep[ browser.locale ] || sep[ browser.language ] || sep['_']);
+    };
+})
+.filter('orderObjectBy', function() {
+  return function(items, field, reverse) {
+    var filtered = [];
+    angular.forEach(items, function(item) {
+      filtered.push(item);
+    });
+    filtered.sort(function (a, b) {
+      return (a[field] > b[field] ? 1 : -1);
+    });
+    if(reverse) filtered.reverse();
+    return filtered;
+  };
+})
+.directive('jstree', function($parse) {
+    return {
+        restrict: 'EA',
+        scope: {
+          data: '=',
+          onSelect: '&'
+        },
+        link: function(scope, element, attrs) {
+            scope.$watch("data", function(newValue, oldValue) {
+                if (newValue) {
+                  var treeConfig = {
+                      "plugins" : [ "themes", "json_data", "ui" ],
+                      "json_data" : {
+                        "data" : scope.data,
+                        "progressive_render" : true
+                      },
+                      "core" : {
+                        "animation" : 0
+                      }
+                  };
+
+                  var tree = $(element).jstree(treeConfig);
+                  tree.jstree('open_node','li:first');
+                  if (tree) {
+                      element.bind("select_node.jstree", function (event, data) {
+                          scope.$apply(function() {
+                              scope.onSelect({url: data.args[0].href, data: data});
+                          });
+                      });
+                  }
+                }
+            }, true);
+        }
+    };
+})
+.directive('connectionMessage', function() {
+  return {
+    link: function($scope, $element, attrs) {
+      var show = function() {$element.css('display', 'block')};
+      var hide = function() {$element.css('display', 'none')};
+      $scope.$on('connectionStatusActive', show);
+      $scope.$on('connectionStatusInactive', hide);
+    }
+  };
+})
+.factory('httpInterceptor', function($q, $rootScope, $timeout, $injector) {
+  var activeRequests = 0;
+
+  var started = function(config) {
+    if (activeRequests == 0) {
+      $rootScope.$broadcast('loadingStatusActive');
+    }
+    if ($rootScope.exceptions[config.url]) {
+      delete $rootScope.exceptions[config.url];
+    }
+    activeRequests++;
+    config.timeout = 10000;
+    return config || $q.when(config);
+  };
+
+  var ended = function(response) {
+    activeRequests--;
+    if (activeRequests == 0) {
+      $rootScope.$broadcast('loadingStatusInactive');
+    }
+    if ($rootScope.retryCount>0) {
+      $rootScope.connectionRecovered = true;
+      $rootScope.retryCount=0;
+      $timeout(function() {
+        $rootScope.connectionRecovered=false;
+        $rootScope.$broadcast('connectionStatusInactive');
+      },2000);
+    }
+    return response || $q.when(response);
+  };
+
+  var failed = function(rejection) {
+    activeRequests--;
+    if (activeRequests == 0) {
+      $rootScope.$broadcast('loadingStatusInactive');
+    }
+    if (rejection.config.headers.doNotIntercept) {
+        return rejection;
+    }
+    if (rejection.status === 0) {
+      $rootScope.$broadcast('connectionStatusActive');
+      if (!$rootScope.retryCount) $rootScope.retryCount=0;
+      $rootScope.retryCount ++;
+      var $http = $injector.get('$http');
+      var result = $http(rejection.config);
+      return result;
+    } else {
+      $rootScope.exceptions[rejection.config.url] = rejection.data.error;
+    }
+    return $q.reject(rejection);
+  }
+
+  return {request: started, response: ended, responseError: failed};
+})
+.config(function($httpProvider) {
+  $httpProvider.interceptors.push("httpInterceptor");
+})
+.directive('fileModel', function ($parse) {
+    return {
+        restrict: 'A',
+        link: function(scope, element, attrs) {
+            var model = $parse(attrs.fileModel);
+            var modelSetter = model.assign;
+
+            element.bind('change', function(){
+                scope.$apply(function(){
+                    modelSetter(scope, element[0].files[0]);
+                });
+            });
+        }
+    };
+});
+
+solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $location, Cores, Collections, System, Ping, Constants) {
+
+  $rootScope.exceptions={};
+
+  $rootScope.toggleException = function() {
+    $scope.showException=!$scope.showException;
+  };
+
+  $scope.refresh = function() {
+      $scope.cores = [];
+      $scope.collections = [];
+  }
+
+  $scope.refresh();
+  $scope.resetMenu = function(page, pageType) {
+    Cores.list(function(data) {
+      $scope.cores = [];
+      var currentCoreName = $route.current.params.core;
+      delete $scope.currentCore;
+      for (key in data.status) {
+        var core = data.status[key];
+        $scope.cores.push(core);
+        if ((!$scope.isSolrCloud || pageType == Constants.IS_CORE_PAGE) && core.name == currentCoreName) {
+            $scope.currentCore = core;
+        }
+      }
+      $scope.showInitFailures = Object.keys(data.initFailures).length>0;
+      $scope.initFailures = data.initFailures;
+    });
+
+    System.get(function(data) {
+      $scope.isCloudEnabled = data.mode.match( /solrcloud/i );
+
+      if ($scope.isCloudEnabled) {
+        Collections.list(function (data) {
+          $scope.collections = [];
+          var currentCollectionName = $route.current.params.core;
+          delete $scope.currentCollection;
+          for (key in data.collections) {
+            var collection = {name: data.collections[key]};
+            $scope.collections.push(collection);
+            if (pageType == Constants.IS_COLLECTION_PAGE && collection.name == currentCollectionName) {
+              $scope.currentCollection = collection;
+            }
+          }
+        })
+      }
+
+    });
+
+    $scope.showingLogging = page.lastIndexOf("logging", 0) === 0;
+    $scope.showingCloud = page.lastIndexOf("cloud", 0) === 0;
+    $scope.page = page;
+  };
+
+  $scope.ping = function() {
+    Ping.ping({core: $scope.currentCore.name}, function(data) {
+      $scope.showPing = true;
+      $scope.pingMS = data.responseHeader.QTime;
+    });
+    // @todo .attr( 'title', '/admin/ping is not configured (' + xhr.status + ': ' + error_thrown + ')' );
+  };
+
+  $scope.dumpCloud = function() {
+      $scope.$broadcast("cloud-dump");
+  }
+
+  $scope.showCore = function(core) {
+    $location.url("/" + core.name);
+  }
+
+  $scope.showCollection = function(collection) {
+    $location.url("/" + collection.name + "/collection-overview")
+  }
+
+  $scope.$on('$routeChangeStart', function() {
+      $rootScope.exceptions = {};
+  });
+});
+
+
+(function(window, angular, undefined) {
+  'use strict';
+
+  angular.module('ngClipboard', []).
+    provider('ngClip', function() {
+      var self = this;
+      this.path = '//cdnjs.cloudflare.com/ajax/libs/zeroclipboard/2.1.6/ZeroClipboard.swf';
+      return {
+        setPath: function(newPath) {
+         self.path = newPath;
+        },
+        setConfig: function(config) {
+          self.config = config;
+        },
+        $get: function() {
+          return {
+            path: self.path,
+            config: self.config
+          };
+        }
+      };
+    }).
+    run(['ngClip', function(ngClip) {
+      var config = {
+        swfPath: ngClip.path,
+        trustedDomains: ["*"],
+        allowScriptAccess: "always",
+        forceHandCursor: true,
+      };
+      ZeroClipboard.config(angular.extend(config,ngClip.config || {}));
+    }]).
+    directive('clipCopy', ['ngClip', function (ngClip) {
+      return {
+        scope: {
+          clipCopy: '&',
+          clipClick: '&',
+          clipClickFallback: '&'
+        },
+        restrict: 'A',
+        link: function (scope, element, attrs) {
+          // Bind a fallback function if flash is unavailable
+          if (ZeroClipboard.isFlashUnusable()) {
+            element.bind('click', function($event) {
+              // Execute the expression with local variables `$event` and `copy`
+              scope.$apply(scope.clipClickFallback({
+                $event: $event,
+                copy: scope.$eval(scope.clipCopy)
+              }));
+            });
+
+            return;
+          }
+
+          // Create the client object
+          var client = new ZeroClipboard(element);
+          if (attrs.clipCopy === "") {
+            scope.clipCopy = function(scope) {
+              return element[0].previousElementSibling.innerText;
+            };
+          }
+          client.on( 'ready', function(readyEvent) {
+
+            client.on('copy', function (event) {
+              var clipboard = event.clipboardData;
+              clipboard.setData(attrs.clipCopyMimeType || 'text/plain', scope.$eval(scope.clipCopy));
+            });
+
+            client.on( 'aftercopy', function(event) {
+              if (angular.isDefined(attrs.clipClick)) {
+                scope.$apply(scope.clipClick);
+              }
+            });
+
+            scope.$on('$destroy', function() {
+              client.destroy();
+            });
+          });
+        }
+      };
+    }]);
+})(window, window.angular);
+
+
+/* THE BELOW CODE IS TAKEN FROM js/scripts/app.js, AND STILL REQUIRES INTEGRATING
+
+
+// @todo clear timeouts
+
+    // activate_core
+    this.before
+    (
+      {},
+      function( context )
+      {
+
+        var menu_wrapper = $( '#menu-wrapper' );
+
+        // global dashboard doesn't have params.splat
+        if( !this.params.splat )
+        {
+          this.params.splat = [ '~index' ];
+        }
+
+        var selector = '~' === this.params.splat[0][0]
+                     ? '#' + this.params.splat[0].replace( /^~/, '' ) + '.global'
+                     : '#core-selector #' + this.params.splat[0].replace( /\./g, '__' );
+
+        var active_element = $( selector, menu_wrapper );
+
+        // @todo "There is no core with this name"
+
+        if( active_element.hasClass( 'global' ) )
+        {
+          active_element
+            .addClass( 'active' );
+
+          if( this.params.splat[1] )
+          {
+            $( '.' + this.params.splat[1], active_element )
+              .addClass( 'active' );
+          }
+
+          $( '#core-selector option[selected]' )
+            .removeAttr( 'selected' )
+            .trigger( 'liszt:updated' );
+
+          $( '#core-selector .chzn-container > a' )
+            .addClass( 'chzn-default' );
+        }
+        else
+        {
+          active_element
+            .attr( 'selected', 'selected' )
+            .trigger( 'liszt:updated' );
+
+
+          $( '#core-menu .' + this.params.splat[1] )
+            .addClass( 'active' );
+
+      }
+    );
+  }
+);
+
+var solr_admin = function( app_config )
+{
+  this.menu_element = $( '#core-selector select' );
+  this.core_menu = $( '#core-menu ul' );
+
+  this.config = config;
+  this.timeout = null;
+
+  this.core_regex_base = '^#\\/([\\w\\d-\\.]+)';
+
+  show_global_error = function( error )
+  {
+    var main = $( '#main' );
+
+    $( 'div[id$="-wrapper"]', main )
+      .remove();
+
+    main
+      .addClass( 'error' )
+      .append( error );
+
+    var pre_tags = $( 'pre', main );
+    if( 0 !== pre_tags.size() )
+    {
+      hljs.highlightBlock( pre_tags.get(0) );
+    }
+  };
+
+  sort_cores_data = function sort_cores_data( cores_status )
+  {
+    // build array of core-names for sorting
+    var core_names = [];
+    for( var core_name in cores_status )
+    {
+      core_names.push( core_name );
+    }
+    core_names.sort();
+
+    var core_count = core_names.length;
+    var cores = {};
+
+    for( var i = 0; i < core_count; i++ )
+    {
+      var core_name = core_names[i];
+      cores[core_name] = cores_status[core_name];
+    }
+
+    return cores;
+  };
+
+  this.set_cores_data = function set_cores_data( cores )
+  {
+    that.cores_data = sort_cores_data( cores.status );
+
+    that.menu_element
+      .empty();
+
+    var core_list = [];
+    core_list.push( '<option></option>' );
+
+    var core_count = 0;
+    for( var core_name in that.cores_data )
+    {
+      core_count++;
+      var core_path = config.solr_path + '/' + core_name;
+      var classes = [];
+
+      if( cores.status[core_name]['isDefaultCore'] )
+      {
+        classes.push( 'default' );
+      }
+
+      var core_tpl = '<option '
+                   + '    id="' + core_name.replace( /\./g, '__' ) + '" '
+                   + '    class="' + classes.join( ' ' ) + '"'
+                   + '    data-basepath="' + core_path + '"'
+                   + '    schema="' + cores.status[core_name]['schema'] + '"'
+                   + '    config="' + cores.status[core_name]['config'] + '"'
+                   + '    value="#/' + core_name + '"'
+                   + '    title="' + core_name + '"'
+                   + '>'
+                   + core_name
+                   + '</option>';
+
+      core_list.push( core_tpl );
+    }
+
+    var has_cores = 0 !== core_count;
+    if( has_cores )
+    {
+      that.menu_element
+        .append( core_list.join( "\n" ) )
+        .trigger( 'liszt:updated' );
+    }
+
+    var core_selector = $( '#core-selector' );
+
+    if( has_cores )
+    {
+      var cores_element = core_selector.find( '#has-cores' );
+      var selector_width = cores_element.width();
+
+      cores_element.find( '.chzn-container' )
+        .css( 'width', selector_width + 'px' );
+
+      cores_element.find( '.chzn-drop' )
+        .css( 'width', ( selector_width - 2 ) + 'px' );
+    }
+  };
+
+  this.run = function()
+  {
+    $.ajax
+    (
+      {
+        // load cores (indexInfo = false
+        success : function( response )
+        {
+
+          var system_url = config.solr_path + '/admin/info/system?wt=json';
+          $.ajax
+          (
+            {
+              url : system_url,
+              dataType : 'json',
+              beforeSend : function( arr, form, options )
+              {
+              },
+              success : function( response )
+              {
+                that.dashboard_values = response;
+
+                var environment_args = null;
+                var cloud_args = null;
+
+                if( response.jvm && response.jvm.jmx && response.jvm.jmx.commandLineArgs )
+                {
+                  var command_line_args = response.jvm.jmx.commandLineArgs.join( ' | ' );
+
+                  environment_args = command_line_args.match( /-Dsolr.environment=((dev|test|prod)?[\w\d]*)/i );
+                }
+
+// @todo detect $scope.isCloud = response.mode.match( /solrcloud/i );
+
+                // environment
+
+                var wrapper = $( '#wrapper' );
+                var environment_element = $( '#environment' );
+                if( environment_args )
+                {
+                  wrapper
+                    .addClass( 'has-environment' );
+
+                  if( environment_args[1] )
+                  {
+                    environment_element
+                      .html( environment_args[1] );
+                  }
+
+                  if( environment_args[2] )
+                  {
+                    environment_element
+                      .addClass( environment_args[2] );
+                  }
+                }
+                else
+                {
+                  wrapper
+                    .removeClass( 'has-environment' );
+                }
+
+                // cloud
+
+                var cloud_nav_element = $( '#menu #cloud' );
+                if( cloud_args )
+                {
+                  cloud_nav_element
+                    .show();
+                }
+
+                // sammy
+
+                sammy.run( location.hash );
+              },
+              error : function()
+              {
+  };
+*/

Added: ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/analysis.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/analysis.js?rev=1776930&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/analysis.js (added)
+++ ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/analysis.js Mon Jan  2 13:44:06 2017
@@ -0,0 +1,203 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+solrAdminApp.controller('AnalysisController',
+  function($scope, $location, $routeParams, Luke, Analysis, Constants) {
+      $scope.resetMenu("analysis", Constants.IS_COLLECTION_PAGE);
+
+      $scope.refresh = function() {
+        Luke.schema({core: $routeParams.core}, function(data) {
+          $scope.fieldsAndTypes = [];
+          for (var field in data.schema.fields) {
+            $scope.fieldsAndTypes.push({
+              group: "Fields",
+              value: "fieldname=" + field,
+              label: field});
+          }
+          for (var type in data.schema.types) {
+            $scope.fieldsAndTypes.push({
+              group: "Types",
+              value: "fieldtype=" + type,
+              label: type});
+          }
+          $scope.core = $routeParams.core;
+        });
+
+        $scope.parseQueryString();
+        // @todo - set defaultSearchField either to context["analysis.fieldname"] or context["analysis.fieldtype"]
+
+      };
+      $scope.verbose = true;
+
+      var getShortComponentName = function(longname) {
+        var short = -1 !== longname.indexOf( '$' )
+                         ? longname.split( '$' )[1]
+                         : longname.split( '.' ).pop();
+        return short.match( /[A-Z]/g ).join( '' );
+      };
+
+      var getCaptionsForComponent = function(data) {
+        var captions = [];
+        for (var key in data[0]) {
+          key = key.replace(/.*#/,'');
+          if (key != "match" && key!="positionHistory") {
+            captions.push(key.replace(/.*#/,''));
+          }
+        }
+        return captions;
+      };
+
+      var getTokensForComponent = function(data) {
+        var tokens = [];
+        var previousPosition = 0;
+        var index=0;
+        for (var i in data) {
+          var tokenhash = data[i];
+          var positionDifference = tokenhash.position - previousPosition;
+          for (var j=positionDifference; j>1; j--) {
+            tokens.push({position: tokenhash.position - j+1, blank:true, index:index++});
+          }
+
+          var token = {position: tokenhash.position, keys:[], index:index++};
+
+          for (key in tokenhash) {
+            if (key == "match" || key=="positionHistory") {
+              //@ todo do something
+            } else {
+              token.keys.push({name:key, value:tokenhash[key]});
+            }
+          }
+          tokens.push(token);
+          previousPosition = tokenhash.position;
+        }
+        return tokens;
+      };
+
+      var extractComponents = function(data, result, name) {
+        if (data) {
+            result[name] = [];
+            for (var i = 0; i < data.length; i += 2) {
+                var component = {
+                    name: data[i],
+                    short: getShortComponentName(data[i]),
+                    captions: getCaptionsForComponent(data[i + 1]),
+                    tokens: getTokensForComponent(data[i + 1])
+                };
+                result[name].push(component);
+            }
+        }
+      };
+
+      var processAnalysisData = function(analysis, fieldOrType) {
+        var fieldname;
+        for (fieldname in analysis[fieldOrType]) {console.log(fieldname);break;}
+        var response = {};
+        extractComponents(analysis[fieldOrType][fieldname].index, response, "index");
+        extractComponents(analysis[fieldOrType][fieldname].query, response, "query");
+        return response;
+      };
+
+      $scope.updateQueryString = function() {
+
+        var parts = $scope.fieldOrType.split("=");
+        var fieldOrType = parts[0];
+        var name = parts[1];
+
+        if ($scope.indexText) {
+            $location.search("analysis.fieldvalue", $scope.indexText);
+        } else if ($location.search()["analysis.fieldvalue"]) {
+            $location.search("analysis.fieldvalue", null);
+        }
+        if ($scope.queryText) {
+          $location.search("analysis.query", $scope.queryText);
+        } else if ($location.search()["analysis.query"]) {
+            $location.search("analysis.query", null);
+        }
+
+        if (fieldOrType == "fieldname") {
+          $location.search("analysis.fieldname", name);
+          $location.search("analysis.fieldtype", null);
+        } else {
+          $location.search("analysis.fieldtype", name);
+          $location.search("analysis.fieldname", null);
+        }
+        $location.search("verbose_output", $scope.verbose ? "1" : "0");
+      };
+
+      $scope.parseQueryString = function () {
+          var params = {};
+          var search = $location.search();
+
+          if (Object.keys(search).length == 0) {
+              return;
+          }
+          for (var key in search) {
+              params[key]=search[key];
+          }
+          $scope.indexText = search["analysis.fieldvalue"];
+          $scope.queryText = search["analysis.query"];
+          if (search["analysis.fieldname"]) {
+              $scope.fieldOrType = "fieldname=" + search["analysis.fieldname"];
+              $scope.schemaBrowserUrl = "field=" + search["analysis.fieldname"];
+          } else {
+              $scope.fieldOrType = "fieldtype=" + search["analysis.fieldtype"];
+              $scope.schemaBrowserUrl = "type=" + search["analysis.fieldtype"];
+          }
+          if (search["verbose_output"] == undefined) {
+            $scope.verbose = true;
+          } else {
+            $scope.verbose = search["verbose_output"] == "1";
+          }
+
+          if ($scope.fieldOrType || $scope.indexText || $scope.queryText) {
+            params.core = $routeParams.core;
+            var parts = $scope.fieldOrType.split("=");
+            var fieldOrType = parts[0] == "fieldname" ? "field_names" : "field_types";
+
+            Analysis.field(params, function(data) {
+              $scope.result = processAnalysisData(data.analysis, fieldOrType);
+            });
+          }
+      };
+
+      $scope.changeFieldOrType = function() {
+        var parts = $scope.fieldOrType.split("=");
+        if (parts[0]=='fieldname') {
+          $scope.schemaBrowserUrl = "field=" + parts[1];
+        } else {
+          $scope.schemaBrowserUrl = "type=" + parts[1];
+        }
+      };
+
+      $scope.toggleVerbose = function() {
+        $scope.verbose = !$scope.verbose;
+        $scope.updateQueryString();
+      };
+
+      $scope.refresh();
+    }
+);
+
+/***************
+
+function(error) {
+  if (error.status == 404) {
+    $scope.isHandlerMissing = true;
+  } else {
+    $scope.analysisError = error.error.msg;
+  }
+****/

Added: ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/cloud.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/cloud.js?rev=1776930&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/cloud.js (added)
+++ ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/cloud.js Mon Jan  2 13:44:06 2017
@@ -0,0 +1,551 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+solrAdminApp.controller('CloudController',
+    function($scope, $location, Zookeeper, Constants) {
+
+        $scope.showDebug = false;
+
+        $scope.$on("cloud-dump", function(event) {
+            $scope.showDebug = true;
+        });
+
+        $scope.closeDebug = function() {
+            $scope.showDebug = false;
+        }
+
+        var view = $location.search().view ? $location.search().view : "graph";
+        if (view == "tree") {
+            $scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE);
+            treeSubController($scope, Zookeeper);
+        } else if (view == "rgraph") {
+            $scope.resetMenu("cloud-rgraph", Constants.IS_ROOT_PAGE);
+            graphSubController($scope, Zookeeper, true);
+        } else if (view == "graph") {
+            $scope.resetMenu("cloud-graph", Constants.IS_ROOT_PAGE);
+            graphSubController($scope, Zookeeper, false);
+        }
+    }
+);
+
+var treeSubController = function($scope, Zookeeper) {
+    $scope.showTree = true;
+    $scope.showGraph = false;
+    $scope.tree = {};
+    $scope.showData = false;
+
+    $scope.showTreeLink = function(link) {
+        var path = decodeURIComponent(link.replace(/.*[\\?&]path=([^&#]*).*/, "$1"));
+        Zookeeper.detail({path: path}, function(data) {
+            $scope.znode = data.znode;
+            var path = data.znode.path.split( '.' );
+            if(path.length >1) {
+              $scope.lang = path.pop();
+            } else {
+              var lastPathElement = data.znode.path.split( '/' ).pop();
+              if (lastPathElement == "managed-schema") {
+                  $scope.lang = "xml";
+              }
+            }
+            $scope.showData = true;
+        });
+    };
+
+    $scope.hideData = function() {
+        $scope.showData = false;
+    };
+
+    $scope.initTree = function() {
+      Zookeeper.simple(function(data) {
+        $scope.tree = data.tree;
+      });
+    };
+
+    $scope.initTree();
+};
+
+var graphSubController = function ($scope, Zookeeper, isRadial) {
+    $scope.showTree = false;
+    $scope.showGraph = true;
+
+    $scope.filterType = "status";
+
+    $scope.helperData = {
+        protocol: [],
+        host: [],
+        hostname: [],
+        port: [],
+        pathname: []
+    };
+
+    $scope.next = function() {
+        $scope.pos += $scope.rows;
+        $scope.initGraph();
+    }
+
+    $scope.previous = function() {
+        $scope.pos = Math.max(0, $scope.pos - $scope.rows);
+        $scope.initGraph();
+    }
+
+    $scope.resetGraph = function() {
+        $scope.pos = 0;
+        $scope.initGraph();
+    }
+
+    $scope.initGraph = function() {
+        Zookeeper.liveNodes(function (data) {
+            var live_nodes = {};
+            for (var c in data.tree[0].children) {
+                live_nodes[data.tree[0].children[c].data.title] = true;
+            }
+
+            var params = {view: "graph"};
+            if ($scope.rows) {
+                params.start = $scope.pos;
+                params.rows = $scope.rows;
+            }
+
+            var filter = ($scope.filterType=='status') ? $scope.pagingStatusFilter : $scope.pagingFilter;
+
+            if (filter) {
+                params.filterType = $scope.filterType;
+                params.filter = filter;
+            }
+
+            Zookeeper.clusterState(params, function (data) {
+                    eval("var state=" + data.znode.data); // @todo fix horrid means to parse JSON
+
+                    var leaf_count = 0;
+                    var graph_data = {
+                        name: null,
+                        children: []
+                    };
+
+                    for (var c in state) {
+                        var shards = [];
+                        for (var s in state[c].shards) {
+                            var nodes = [];
+                            for (var n in state[c].shards[s].replicas) {
+                                leaf_count++;
+                                var replica = state[c].shards[s].replicas[n]
+
+                                var uri = replica.base_url;
+                                var parts = uri.match(/^(\w+:)\/\/(([\w\d\.-]+)(:(\d+))?)(.+)$/);
+                                var uri_parts = {
+                                    protocol: parts[1],
+                                    host: parts[2],
+                                    hostname: parts[3],
+                                    port: parseInt(parts[5] || 80, 10),
+                                    pathname: parts[6]
+                                };
+
+                                $scope.helperData.protocol.push(uri_parts.protocol);
+                                $scope.helperData.host.push(uri_parts.host);
+                                $scope.helperData.hostname.push(uri_parts.hostname);
+                                $scope.helperData.port.push(uri_parts.port);
+                                $scope.helperData.pathname.push(uri_parts.pathname);
+
+                                var status = replica.state;
+
+                                if (!live_nodes[replica.node_name]) {
+                                    status = 'gone';
+                                }
+
+                                var node = {
+                                    name: uri,
+                                    data: {
+                                        type: 'node',
+                                        state: status,
+                                        leader: 'true' === replica.leader,
+                                        uri: uri_parts
+                                    }
+                                };
+                                nodes.push(node);
+                            }
+
+                            var shard = {
+                                name: s,
+                                data: {
+                                    type: 'shard'
+                                },
+                                children: nodes
+                            };
+                            shards.push(shard);
+                        }
+
+                        var collection = {
+                            name: c,
+                            data: {
+                                type: 'collection'
+                            },
+                            children: shards
+                        };
+                        graph_data.children.push(collection);
+                    }
+
+                    $scope.helperData.protocol = $.unique($scope.helperData.protocol);
+                    $scope.helperData.host = $.unique($scope.helperData.host);
+                    $scope.helperData.hostname = $.unique($scope.helperData.hostname);
+                    $scope.helperData.port = $.unique($scope.helperData.port);
+                    $scope.helperData.pathname = $.unique($scope.helperData.pathname);
+
+                    if (!isRadial && data.znode && data.znode.paging) {
+                        $scope.showPaging = true;
+
+                        var parr = data.znode.paging.split('|');
+                        if (parr.length < 3) {
+                            $scope.showPaging = false;
+                        } else {
+                            $scope.start = Math.max(parseInt(parr[0]), 0);
+                            $scope.prevEnabled = ($scope.start > 0);
+                            $scope.rows = parseInt(parr[1]);
+                            $scope.total = parseInt(parr[2]);
+
+                            if ($scope.rows == -1) {
+                                $scope.showPaging = false;
+                            } else {
+                                var filterType = parr.length > 3 ? parr[3] : '';
+
+                                if (filterType == '' || filterType == 'none') filterType = 'status';
+
+                                +$('#cloudGraphPagingFilterType').val(filterType);
+
+                                var filter = parr.length > 4 ? parr[4] : '';
+                                var page = Math.floor($scope.start / $scope.rows) + 1;
+                                var pages = Math.ceil($scope.total / $scope.rows);
+                                $scope.last = Math.min($scope.start + $scope.rows, $scope.total);
+                                $scope.nextEnabled = ($scope.last < $scope.total);
+                            }
+                        }
+                    }
+                    else {
+                        $scope.showPaging = false;
+                    }
+                    $scope.graphData = graph_data;
+                    $scope.leafCount = leaf_count;
+                    $scope.isRadial = isRadial;
+                });
+        });
+    };
+
+    $scope.initGraph();
+};
+
+solrAdminApp.directive('graph', function(Constants) {
+    return {
+        restrict: 'EA',
+        scope: {
+            data: "=",
+            leafCount: "=",
+            helperData: "=",
+            isRadial: "="
+        },
+        link: function (scope, element, attrs) {
+            var helper_path_class = function (p) {
+                var classes = ['link'];
+                classes.push('lvl-' + p.target.depth);
+
+                if (p.target.data && p.target.data.leader) {
+                    classes.push('leader');
+                }
+
+                if (p.target.data && p.target.data.state) {
+                    classes.push(p.target.data.state);
+                }
+
+                return classes.join(' ');
+            };
+
+            var helper_node_class = function (d) {
+                var classes = ['node'];
+                classes.push('lvl-' + d.depth);
+
+                if (d.data && d.data.leader) {
+                    classes.push('leader');
+                }
+
+                if (d.data && d.data.state) {
+                    classes.push(d.data.state);
+                }
+
+                return classes.join(' ');
+            };
+
+            var helper_node_text = function (d) {
+                if (!d.data || !d.data.uri) {
+                    return d.name;
+                }
+
+                var name = d.data.uri.hostname;
+
+                if (1 !== scope.helperData.protocol.length) {
+                    name = d.data.uri.protocol + '//' + name;
+                }
+
+                if (1 !== scope.helperData.port.length) {
+                    name += ':' + d.data.uri.port;
+                }
+
+                if (1 !== scope.helperData.pathname.length) {
+                    name += d.data.uri.pathname;
+                }
+
+                return name;
+            };
+
+            scope.$watch("data", function(newValue, oldValue) {
+                if (newValue) {
+                    if (scope.isRadial) {
+                        radialGraph(element, scope.data, scope.leafCount);
+                    } else {
+                        flatGraph(element, scope.data, scope.leafCount);
+                    }
+                }
+            });
+
+
+            function setNodeNavigationBehavior(node, view){
+                node
+                .attr('data-href', function (d) {
+                    if (d.type == "node"){
+                        return getNodeUrl(d, view);
+                    }
+                    else{
+                        return "";
+                    }
+                })
+                .on('click', function(d) {
+                    if (d.data.type == "node"){
+                        location.href = getNodeUrl(d, view);
+                    }
+                });
+            }
+
+            function getNodeUrl(d, view){
+                var url = d.name + Constants.ROOT_URL + "#/~cloud";
+                if (view != undefined){
+                    url += "?view=" + view;
+                }
+                return url;
+            }
+
+            var flatGraph = function(element, graphData, leafCount) {
+                var w = element.width(),
+                    h = leafCount * 20;
+
+                var tree = d3.layout.tree().size([h, w - 400]);
+
+                var diagonal = d3.svg.diagonal().projection(function (d) {
+                    return [d.y, d.x];
+                });
+
+                d3.select('#canvas', element).html('');
+                var vis = d3.select('#canvas', element).append('svg')
+                    .attr('width', w)
+                    .attr('height', h)
+                    .append('g')
+                    .attr('transform', 'translate(100, 0)');
+
+                var nodes = tree.nodes(graphData);
+
+                var link = vis.selectAll('path.link')
+                    .data(tree.links(nodes))
+                    .enter().append('path')
+                    .attr('class', helper_path_class)
+                    .attr('d', diagonal);
+
+                var node = vis.selectAll('g.node')
+                    .data(nodes)
+                    .enter().append('g')
+                    .attr('class', helper_node_class)
+                    .attr('transform', function (d) {
+                        return 'translate(' + d.y + ',' + d.x + ')';
+                    })
+
+                node.append('circle')
+                    .attr('r', 4.5);
+
+                node.append('text')
+                    .attr('dx', function (d) {
+                        return 0 === d.depth ? -8 : 8;
+                    })
+                    .attr('dy', function (d) {
+                        return 5;
+                    })
+                    .attr('text-anchor', function (d) {
+                        return 0 === d.depth ? 'end' : 'start';
+                    })                    
+                    .text(helper_node_text);
+
+                setNodeNavigationBehavior(node);
+            };
+
+            var radialGraph = function(element, graphData, leafCount) {
+                var max_val = Math.min(element.width(), $('body').height())
+                var r = max_val / 2;
+
+                var cluster = d3.layout.cluster()
+                    .size([360, r - 160]);
+
+                var diagonal = d3.svg.diagonal.radial()
+                    .projection(function (d) {
+                        return [d.y, d.x / 180 * Math.PI];
+                    });
+
+                d3.select('#canvas', element).html('');
+                var vis = d3.select('#canvas').append('svg')
+                    .attr('width', r * 2)
+                    .attr('height', r * 2)
+                    .append('g')
+                    .attr('transform', 'translate(' + r + ',' + r + ')');
+
+                var nodes = cluster.nodes(graphData);
+
+                var link = vis.selectAll('path.link')
+                    .data(cluster.links(nodes))
+                    .enter().append('path')
+                    .attr('class', helper_path_class)
+                    .attr('d', diagonal);
+
+                var node = vis.selectAll('g.node')
+                    .data(nodes)
+                    .enter().append('g')
+                    .attr('class', helper_node_class)
+                    .attr('transform', function (d) {
+                        return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')';
+                    })
+
+                node.append('circle')
+                    .attr('r', 4.5);
+
+                node.append('text')
+                    .attr('dx', function (d) {
+                        return d.x < 180 ? 8 : -8;
+                    })
+                    .attr('dy', '.31em')
+                    .attr('text-anchor', function (d) {
+                        return d.x < 180 ? 'start' : 'end';
+                    })
+                    .attr('transform', function (d) {
+                        return d.x < 180 ? null : 'rotate(180)';
+                    })
+                    .text(helper_node_text);
+
+                setNodeNavigationBehavior(node, "rgraph");
+            }
+        }
+    };
+})
+
+/*
+
+========================
+var init_debug = function( cloud_element )
+{
+  var debug_element = $( '#debug', cloud_element );
+  var debug_button = $( '#menu #cloud .dump a' );
+
+  var clipboard_element = $( '.clipboard', debug_element );
+  var clipboard_button = $( 'a', clipboard_element );
+
+  $( '.clipboard', debug_element )
+    .die( 'click' )
+    .live
+    (
+      'click',
+      function( event )
+      {
+        return false;
+      }
+    );
+
+            url : app.config.solr_path + '/zookeeper?wt=json&dump=true',
+              ZeroClipboard.setMoviePath( 'img/ZeroClipboard.swf' );
+
+              clipboard_client = new ZeroClipboard.Client();
+
+              clipboard_client.addEventListener
+              (
+                'load',
+                function( client )
+                {
+                }
+              );
+
+              clipboard_client.addEventListener
+              (
+                'complete',
+                function( client, text )
+                {
+                  clipboard_element
+                    .addClass( 'copied' );
+
+                  clipboard_button
+                    .data( 'text', clipboard_button.text() )
+                    .text( clipboard_button.data( 'copied' ) );
+                }
+              );
+            },
+            success : function( response, text_status, xhr )
+            {
+              clipboard_client.glue
+              (
+                clipboard_element.get(0),
+                clipboard_button.get(0)
+              );
+
+              clipboard_client.setText( response.replace( /\\/g, '\\\\' ) );
+
+              $( '.debug', debug_element )
+                .removeClass( 'loader' )
+                .text( response );
+            },
+            error : function( xhr, text_status, error_thrown )
+            {
+            },
+            complete : function( xhr, text_status )
+            {
+            }
+          }
+        );
+      }
+    )
+    .die( 'hide' )
+    .live
+    (
+      'hide',
+      function( event )
+      {
+        $( '.debug', debug_element )
+          .empty();
+
+        clipboard_element
+          .removeClass( 'copied' );
+
+        clipboard_button
+          .data( 'copied', clipboard_button.text() )
+          .text( clipboard_button.data( 'text' ) );
+
+        clipboard_client.destroy();
+
+        debug_element.hide();
+      }
+    );
+};
+
+*/

Added: ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collection-overview.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collection-overview.js?rev=1776930&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collection-overview.js (added)
+++ ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collection-overview.js Mon Jan  2 13:44:06 2017
@@ -0,0 +1,39 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+solrAdminApp.controller('CollectionOverviewController',
+function($scope, $routeParams, Collections, Constants) {
+  $scope.resetMenu("collection-overview", Constants.IS_COLLECTION_PAGE);
+
+  $scope.refresh = function() {
+    Collections.status({}, function(data) {
+      $scope.selectedCollection = data.cluster.collections[$routeParams.core];
+      $scope.selectedCollection.name = $routeParams.core;
+      $scope.rootUrl = Constants.ROOT_URL;
+    });
+  };
+
+  $scope.showReplica = function(replica) {
+    replica.show = !replica.show;
+  }
+
+  $scope.hideShard = function(shard) {
+    shard.hide = !shard.hide;
+  }
+
+  $scope.refresh();
+});

Added: ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collections.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collections.js?rev=1776930&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collections.js (added)
+++ ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/collections.js Mon Jan  2 13:44:06 2017
@@ -0,0 +1,260 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+// @todo test optimize (delete stuff, watch button appear, test button/form)
+solrAdminApp.controller('CollectionsController',
+    function($scope, $routeParams, $location, $timeout, Collections, Zookeeper, Constants){
+      $scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
+
+      $scope.refresh = function() {
+
+          $scope.rootUrl = Constants.ROOT_URL + "#/~collections/" + $routeParams.collection;
+
+          Collections.status(function (data) {
+              $scope.collections = [];
+              for (var name in data.cluster.collections) {
+                  var collection = data.cluster.collections[name];
+                  collection.name = name;
+                  var shards = collection.shards;
+                  collection.shards = [];
+                  for (var shardName in shards) {
+                      var shard = shards[shardName];
+                      shard.name = shardName;
+                      shard.collection = collection.name;
+                      var replicas = shard.replicas;
+                      shard.replicas = [];
+                      for (var replicaName in replicas) {
+                          var replica = replicas[replicaName];
+                          replica.name = replicaName;
+                          replica.collection = collection.name;
+                          replica.shard = shard.name;
+                          shard.replicas.push(replica);
+                      }
+                      collection.shards.push(shard);
+                  }
+                  $scope.collections.push(collection);
+                  if ($routeParams.collection == name) {
+                      $scope.collection = collection;
+                  }
+              }
+              if ($routeParams.collection && !$scope.collection) {
+                  alert("No collection called " + $routeParams.collection)
+                  $location.path("/~collections");
+              }
+              $scope.liveNodes = data.cluster.liveNodes;
+          });
+          Zookeeper.configs(function(data) {
+              $scope.configs = [];
+              var items = data.tree[0].children;
+              for (var i in items) {
+                  $scope.configs.push({name: items[i].data.title});
+              }
+          });
+      };
+
+      $scope.hideAll = function() {
+          $scope.showRename = false;
+          $scope.showAdd = false;
+          $scope.showDelete = false;
+          $scope.showSwap = false;
+          $scope.showCreateAlias = false;
+          $scope.showDeleteAlias = false;
+      };
+
+      $scope.showAddCollection = function() {
+        $scope.hideAll();
+        $scope.showAdd = true;
+        $scope.newCollection = {
+          name: "",
+          routerName: "compositeId",
+          numShards: 1,
+          configName: "",
+          replicationFactor: 1,
+          maxShardsPerNode: 1
+        };
+      };
+
+      $scope.toggleCreateAlias = function() {
+        $scope.hideAll();
+        $scope.showCreateAlias = true;
+      }
+
+      $scope.toggleDeleteAlias = function() {
+        $scope.hideAll();
+        $scope.showDeleteAlias = true;
+        Zookeeper.aliases({}, function(data){
+          if (Object.keys(data.aliases).length == 0) {
+            delete $scope.aliases;
+          } else {
+            $scope.aliases = data.aliases;
+          }
+        });
+
+      }
+
+      $scope.cancelCreateAlias = $scope.cancelDeleteAlias = function() {
+        $scope.hideAll();
+      }
+
+      $scope.createAlias = function() {
+        var collections = [];
+        for (var i in $scope.aliasCollections) {
+          collections.push($scope.aliasCollections[i].name);
+        }
+        Collections.createAlias({name: $scope.aliasToCreate, collections: collections.join(",")}, function(data) {
+          $scope.hideAll();
+        });
+      }
+      $scope.deleteAlias = function() {
+        Collections.deleteAlias({name: $scope.aliasToDelete}, function(data) {
+          $scope.hideAll();
+        });
+
+      };
+      $scope.addCollection = function() {
+        if (!$scope.newCollection.name) {
+          $scope.addMessage = "Please provide a core name";
+        } else if (false) { //@todo detect whether core exists
+          $scope.AddMessage = "A core with that name already exists";
+        } else {
+            var coll = $scope.newCollection;
+            var params = {
+                name: coll.name,
+                "router.name": coll.routerName,
+                numShards: coll.numShards,
+                "collection.configName": coll.configName,
+                replicationFactor: coll.replicationFactor,
+                maxShardsPerNode: coll.maxShardsPerNode
+            };
+            if (coll.shards) params.shards = coll.shards;
+            if (coll.routerField) params.routerField = coll.routerField;
+            if (coll.routerName) params.routerName = coll.routerName;
+            Collections.add(params, function(data) {
+              $scope.cancelAddCollection();
+              $scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
+              $location.path("/~collections/" + $scope.newCollection.name);
+            });
+        }
+      };
+
+      $scope.cancelAddCollection = function() {
+        delete $scope.addMessage;
+        $scope.showAdd = false;
+      };
+
+      $scope.showDeleteCollection = function() {
+          $scope.hideAll();
+          if ($scope.collection) {
+              $scope.showDelete = true;
+          } else {
+              alert("No collection selected.");
+          }
+      };
+
+      $scope.deleteCollection = function() {
+        if ($scope.collection.name == $scope.collectionDeleteConfirm) {
+            Collections.delete({name: $scope.collection.name}, function (data) {
+                $location.path("/~collections");
+            });
+        } else {
+            $scope.deleteMessage = "Collection names do not match.";
+        }
+      };
+
+      $scope.reloadCollection = function() {
+        if (!$scope.collection) {
+            alert("No collection selected.");
+            return;
+        }
+        Collections.reload({name: $scope.collection.name},
+          function(successData) {
+            $scope.reloadSuccess = true;
+            $timeout(function() {$scope.reloadSuccess=false}, 1000);
+          },
+          function(failureData) {
+            $scope.reloadFailure = true;
+            $timeout(function() {$scope.reloadFailure=false}, 1000);
+            $location.path("/~collections");
+          });
+      };
+
+      $scope.toggleAddReplica = function(shard) {
+          $scope.hideAll();
+          shard.showAdd = !shard.showAdd;
+          delete $scope.addReplicaMessage;
+
+          Zookeeper.liveNodes({}, function(data) {
+            $scope.nodes = [];
+            var children = data.tree[0].children;
+            for (var child in children) {
+              $scope.nodes.push(children[child].data.title);
+            }
+          });
+      };
+
+      $scope.toggleRemoveReplica = function(replica) {
+          $scope.hideAll();
+          replica.showRemove = !replica.showRemove;
+      };
+
+      $scope.deleteReplica = function(replica) {
+        Collections.deleteReplica({collection: replica.collection, shard:replica.shard, replica:replica.name}, function(data) {
+          replica.deleted = true;
+          $timeout(function() {
+            $scope.refresh();
+          }, 2000);
+        });
+      }
+      $scope.addReplica = function(shard) {
+        var params = {
+          collection: shard.collection,
+          shard: shard.name,
+        }
+        if (shard.replicaNodeName && shard.replicaNodeName != "") {
+          params.node = shard.replicaNodeName;
+        }
+        Collections.addReplica(params, function(data) {
+          shard.replicaAdded = true;
+          $timeout(function () {
+            shard.replicaAdded = false;
+            shard.showAdd = false;
+            $$scope.refresh();
+          }, 2000);
+        });
+      };
+
+      $scope.toggleShard = function(shard) {
+          shard.show = !shard.show;
+      }
+
+      $scope.toggleReplica = function(replica) {
+          replica.show = !replica.show;
+      }
+
+      $scope.refresh();
+    }
+);
+
+var flatten = function(data) {
+    var list = [];
+    for (var name in data) {
+       var entry = data[name];
+        entry.name = name;
+        list.push(entry);
+    }
+    return list;
+}

Added: ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/core-overview.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/core-overview.js?rev=1776930&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/core-overview.js (added)
+++ ofbiz/trunk/specialpurpose/solr/webapp/solr/js/angular/controllers/core-overview.js Mon Jan  2 13:44:06 2017
@@ -0,0 +1,224 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+solrAdminApp.controller('CoreOverviewController',
+function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication, Ping, Constants) {
+  $scope.resetMenu("overview", Constants.IS_CORE_PAGE);
+  $scope.refreshIndex = function() {
+    Luke.index({core: $routeParams.core},
+      function(data) {
+        $scope.index = data.index;
+        delete $scope.statsMessage;
+      },
+      function(error) {
+        $scope.statsMessage = "Luke is not configured";
+      }
+    );
+  };
+
+  $scope.optimizeIndex = function(core) {
+    Update.optimize({core: $routeParams.core},
+      function(response) {
+        $scope.refresh();
+        delete $scope.indexMessage;
+      },
+      function(error) {
+        $scope.statisticsDisabled = true;
+        $scope.indexMessage = "Optimize broken.";
+      });
+  };
+
+  $scope.refreshReplication = function() {
+    Replication.details({core: $routeParams.core},
+      function(data) {
+        $scope.isSlave = data.details.isSlave == "true";
+        $scope.isMaster = data.details.isMaster == "true";
+        $scope.replication = data.details;
+      },
+      function(error) {
+        $scope.replicationMessage = "Replication is not configured";
+      });
+  /*
+      /replication?command=details&wt=json
+
+              if( is_slave )
+              {
+
+                // warnings if slave version|gen doesn't match what's replicable
+                if( data.indexVersion !== master_data.master.replicableVersion )
+                {
+                  $( '.version', details_element )
+                    .addClass( 'diff' );
+                }
+                else
+                {
+                  $( '.version', details_element )
+                    .removeClass( 'diff' );
+                }
+
+                if( data.generation !== master_data.master.replicableGeneration )
+                {
+                  $( '.generation', details_element )
+                    .addClass( 'diff' );
+                }
+                else
+                {
+                  $( '.generation', details_element )
+                    .removeClass( 'diff' );
+                }
+              }
+            },
+
+*/
+  };
+
+  $scope.refreshAdminExtra = function() {
+  };
+
+  $scope.refreshSystem = function() {
+    CoreSystem.get({core: $routeParams.core},
+      function(data) {
+        $scope.core = data.core;
+        delete $scope.systemMessage;
+      },
+      function(error) {
+        $scope.systemMessage = "/admin/system Handler is not configured";
+      }
+    );
+  };
+
+  $scope.refreshPing = function() {
+    Ping.status({core: $routeParams.core}, function(data) {
+      if (data.error) {
+        $scope.healthcheckStatus = false;
+        if (data.error.code == 503) {
+          $scope.healthcheckMessage = 'Ping request handler is not configured with a healthcheck file.';
+        }
+      } else {
+        $scope.healthcheckStatus = data.status == "enabled";
+      }
+    });
+  };
+
+  $scope.toggleHealthcheck = function() {
+    if ($scope.healthcheckStatus) {
+      Ping.disable(
+        function(data) {$scope.healthcheckStatus = false},
+        function(error) {$scope.healthcheckMessage = error}
+      );
+    } else {
+      Ping.enable(
+        function(data) {$scope.healthcheckStatus = true},
+        function(error) {$scope.healthcheckMessage = error}
+      );
+    }
+  };
+
+  $scope.refresh = function() {
+    $scope.refreshIndex();
+    $scope.refreshReplication();
+    $scope.refreshAdminExtra();
+    $scope.refreshSystem();
+    $scope.refreshPing();
+  };
+
+  $scope.refresh();
+});
+
+/*******
+
+// @todo admin-extra
+    var core_basepath = this.active_core.attr( 'data-basepath' );
+    var content_element = $( '#content' );
+
+    content_element
+      .removeClass( 'single' );
+
+    if( !app.core_menu.data( 'admin-extra-loaded' ) )
+    {
+      app.core_menu.data( 'admin-extra-loaded', new Date() );
+
+      $.get
+      (
+        core_basepath + '/admin/file/?file=admin-extra.menu-top.html&contentType=text/html;charset=utf-8',
+        function( menu_extra )
+        {
+          app.core_menu
+            .prepend( menu_extra );
+        }
+      );
+
+      $.get
+      (
+        core_basepath + '/admin/file/?file=admin-extra.menu-bottom.html&contentType=text/html;charset=utf-8',
+        function( menu_extra )
+        {
+          app.core_menu
+            .append( menu_extra );
+        }
+      );
+    }
+
+
+
+////////////////////////////////// ADMIN EXTRA
+        $.ajax
+        (
+          {
+            url : core_basepath + '/admin/file/?file=admin-extra.html',
+            dataType : 'html',
+            context : $( '#admin-extra', dashboard_element ),
+            beforeSend : function( xhr, settings )
+            {
+              $( 'h2', this )
+                .addClass( 'loader' );
+
+              $( '.message', this )
+                .show()
+                .html( 'Loading' );
+
+              $( '.content', this )
+                .hide();
+            },
+            success : function( response, text_status, xhr )
+            {
+              $( '.message', this )
+                .hide()
+                .empty();
+
+              $( '.content', this )
+                .show()
+                .html( response );
+            },
+            error : function( xhr, text_status, error_thrown)
+            {
+              this
+                .addClass( 'disabled' );
+
+              $( '.message', this )
+                .show()
+                .html( 'We found no "admin-extra.html" file.' );
+            },
+            complete : function( xhr, text_status )
+            {
+              $( 'h2', this )
+                .removeClass( 'loader' );
+            }
+          }
+        );
+
+***/