You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by er...@apache.org on 2015/05/19 00:35:59 UTC

svn commit: r1680118 [1/2] - in /lucene/dev/trunk/solr: ./ webapp/web/ webapp/web/css/angular/ webapp/web/js/angular/ webapp/web/js/angular/controllers/ webapp/web/partials/

Author: erick
Date: Mon May 18 22:35:59 2015
New Revision: 1680118

URL: http://svn.apache.org/r1680118
Log:
SOLR-7558: Uber-patch for Angular JS admin UI

Added:
    lucene/dev/trunk/solr/webapp/web/css/angular/dataimport.css   (with props)
    lucene/dev/trunk/solr/webapp/web/css/angular/replication.css   (with props)
    lucene/dev/trunk/solr/webapp/web/css/angular/schema-browser.css   (with props)
    lucene/dev/trunk/solr/webapp/web/css/angular/segments.css   (with props)
    lucene/dev/trunk/solr/webapp/web/js/angular/controllers/dataimport.js   (with props)
    lucene/dev/trunk/solr/webapp/web/js/angular/controllers/replication.js   (with props)
    lucene/dev/trunk/solr/webapp/web/js/angular/controllers/schema-browser.js   (with props)
    lucene/dev/trunk/solr/webapp/web/js/angular/controllers/segments.js   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/dataimport.html   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/documents.html   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/files.html   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/plugins.html   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/replication.html   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/schema-browser.html   (with props)
    lucene/dev/trunk/solr/webapp/web/partials/segments.html   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/webapp/web/css/angular/chosen.css
    lucene/dev/trunk/solr/webapp/web/css/angular/common.css
    lucene/dev/trunk/solr/webapp/web/css/angular/menu.css
    lucene/dev/trunk/solr/webapp/web/index.html
    lucene/dev/trunk/solr/webapp/web/js/angular/app.js
    lucene/dev/trunk/solr/webapp/web/js/angular/services.js
    lucene/dev/trunk/solr/webapp/web/partials/analysis.html
    lucene/dev/trunk/solr/webapp/web/partials/cloud.html
    lucene/dev/trunk/solr/webapp/web/partials/core_overview.html
    lucene/dev/trunk/solr/webapp/web/partials/logging.html

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1680118&r1=1680117&r2=1680118&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Mon May 18 22:35:59 2015
@@ -129,8 +129,9 @@ New Features
     http://localhost:8983/solr/techproducts/replication?command=restorestatus
   (Varun Thacker, noble, shalin)
 
-* SOLR-7241, SOLR-7263, SOLR-7279: More functionality moving the Admin UI to Angular JS
-  (Upayavira via Erick)
+* SOLR-7241, SOLR-7263, SOLR-7279, SOLR-7300, SOLR-7396, SOLR-7397, SOLR-7492: 
+  Admin UI - Refactoring using AngularJS. More functionality moving the Admin 
+  UI to Angular JS (Upayavira via Erick)
 
 * SOLR-7372: Limit memory consumed by LRUCache with a new 'maxRamMB' config parameter.
   (yonik, shalin)

Modified: lucene/dev/trunk/solr/webapp/web/css/angular/chosen.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/chosen.css?rev=1680118&r1=1680117&r2=1680118&view=diff
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/chosen.css (original)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/chosen.css Mon May 18 22:35:59 2015
@@ -116,7 +116,7 @@ This file is generated by `grunt build`,
   display: block;
   width: 12px;
   height: 12px;
-  background: url('chosen-sprite.png') -42px 1px no-repeat;
+  background: url('../../img/chosen-sprite.png') -42px 1px no-repeat;
   font-size: 1px;
 }
 .chosen-container-single .chosen-single abbr:hover {
@@ -137,7 +137,7 @@ This file is generated by `grunt build`,
   display: block;
   width: 100%;
   height: 100%;
-  background: url('chosen-sprite.png') no-repeat 0px 2px;
+  background: url('../../img/chosen-sprite.png') no-repeat 0px 2px;
 }
 .chosen-container-single .chosen-search {
   position: relative;
@@ -153,8 +153,8 @@ This file is generated by `grunt build`,
   height: auto;
   outline: 0;
   border: 1px solid #aaa;
-  background: white url('chosen-sprite.png') no-repeat 100% -20px;
-  background: url('chosen-sprite.png') no-repeat 100% -20px;
+  background: white url('../../img/chosen-sprite.png') no-repeat 100% -20px;
+  background: url('../../img/chosen-sprite.png') no-repeat 100% -20px;
   font-size: 1em;
   font-family: sans-serif;
   line-height: normal;
@@ -300,7 +300,7 @@ This file is generated by `grunt build`,
   display: block;
   width: 12px;
   height: 12px;
-  background: url('chosen-sprite.png') -42px 1px no-repeat;
+  background: url('../../img/chosen-sprite.png') -42px 1px no-repeat;
   font-size: 1px;
 }
 .chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
@@ -436,8 +436,8 @@ This file is generated by `grunt build`,
 }
 .chosen-rtl .chosen-search input[type="text"] {
   padding: 4px 5px 4px 20px;
-  background: white url('chosen-sprite.png') no-repeat -30px -20px;
-  background: url('chosen-sprite.png') no-repeat -30px -20px;
+  background: white url('../../img/chosen-sprite.png') no-repeat -30px -20px;
+  background: url('../../img/chosen-sprite.png') no-repeat -30px -20px;
   direction: rtl;
 }
 .chosen-rtl.chosen-container-single .chosen-single div b {
@@ -457,7 +457,7 @@ This file is generated by `grunt build`,
   .chosen-container-multi .chosen-choices .search-choice .search-choice-close,
   .chosen-container .chosen-results-scroll-down span,
   .chosen-container .chosen-results-scroll-up span {
-    background-image: url('chosen-sprite@2x.png') !important;
+    background-image: url('../../img/chosen-sprite-2x.png') !important;
     background-size: 52px 37px !important;
     background-repeat: no-repeat !important;
   }

Modified: lucene/dev/trunk/solr/webapp/web/css/angular/common.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/common.css?rev=1680118&r1=1680117&r2=1680118&view=diff
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/common.css (original)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/common.css Mon May 18 22:35:59 2015
@@ -180,6 +180,12 @@ ul
   background-image: url( ../../img/loader-light.gif ) !important;
 }
 
+.universal-loader {
+  position: absolute;
+  left: 0px;
+  top: 0px;
+}
+
 #wrapper
 {
   position: relative;

Added: lucene/dev/trunk/solr/webapp/web/css/angular/dataimport.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/dataimport.css?rev=1680118&view=auto
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/dataimport.css (added)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/dataimport.css Mon May 18 22:35:59 2015
@@ -0,0 +1,370 @@
+/*
+
+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.
+
+*/
+
+#content #dataimport
+{
+  background-image: url( ../../img/div.gif );
+  background-position: 21% 0;
+  background-repeat: repeat-y;
+}
+
+#content #dataimport #frame
+{
+  float: right;
+  width: 78%;
+}
+
+#content #dataimport #form
+{
+  float: left;
+  width: 20%;
+}
+
+#content #dataimport #form #navigation
+{
+  border-right: 0;
+}
+
+#content #dataimport #form #navigation a
+{
+  background-image: url( ../../img/ico/status-offline.png );
+}
+
+#content #dataimport #form #navigation .current a
+{
+  background-image: url( ../../img/ico/status.png );
+}
+
+#content #dataimport #form form
+{
+  border-top: 1px solid #f0f0f0;
+  margin-top: 10px;
+  padding-top: 5px;
+}
+
+#content #dataimport #form label
+{
+  cursor: pointer;
+  display: block;
+  margin-top: 5px;
+}
+
+#content #dataimport #form input,
+#content #dataimport #form select,
+#content #dataimport #form textarea
+{
+  margin-bottom: 2px;
+  width: 100%;
+}
+
+#content #dataimport #form input
+{
+  width: 98%;
+}
+
+#content #dataimport #form button
+{
+  margin-top: 10px;
+}
+
+#content #dataimport #form .execute span
+{
+  background-image: url( ../../img/ico/document-import.png );
+}
+
+#content #dataimport #form .refresh-status span
+{
+  background-image: url( ../../img/ico/arrow-circle.png );
+}
+
+#content #dataimport #form .refresh-status span.success
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #dataimport #form #start
+{
+  float: left;
+  width: 47%;
+}
+
+#content #dataimport #form #rows
+{
+  float: right;
+  width: 47%;
+}
+
+#content #dataimport #form .checkbox input
+{
+  margin-bottom: 0;
+  width: auto;
+}
+
+#content #dataimport #form #auto-refresh-status
+{
+  margin-top: 20px;
+}
+
+#content #dataimport #form #auto-refresh-status a
+{
+  background-image: url( ../../img/ico/ui-check-box-uncheck.png );
+  background-position: 0 50%;
+  color: #c0c0c0;
+  display: block;
+  padding-left: 21px;
+}
+
+#content #dataimport #form #auto-refresh-status a.on,
+#content #dataimport #form #auto-refresh-status a:hover
+{
+  color: #333;
+}
+
+#content #dataimport #form #auto-refresh-status a.on
+{
+  background-image: url( ../../img/ico/ui-check-box.png );
+}
+
+#content #dataimport #current_state
+{
+  padding: 10px;
+  margin-bottom: 20px;
+}
+
+#content #dataimport #current_state .last_update,
+#content #dataimport #current_state .info
+{
+  display: block;
+  padding-left: 21px;
+}
+
+#content #dataimport #current_state .last_update
+{
+  color: #c0c0c0;
+  font-size: 11px;
+}
+
+#content #dataimport #current_state .info
+{
+  background-position: 0 1px;
+  position: relative;
+}
+
+#content #dataimport #current_state .info .details span
+{
+#  color: #c0c0c0;
+}
+
+#content #dataimport #current_state .info .abort-import
+{
+  position: absolute;
+  right: 0px;
+  top: 0px;
+}
+
+#content #dataimport #current_state .info .abort-import span
+{
+  background-image: url( ../../img/ico/cross.png );
+}
+
+#content #dataimport #current_state .info .abort-import.success span
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #dataimport #current_state.indexing
+{
+  background-color: #f9f9f9;
+}
+
+#content #dataimport #current_state.indexing .info
+{
+  background-image: url( ../../img/ico/hourglass.png );
+}
+
+#content #dataimport #current_state.indexing .info .abort-import
+{
+  display: block;
+}
+
+#content #dataimport #current_state.success
+{
+  background-color: #e6f3e6;
+}
+
+#content #dataimport #current_state.success .info
+{
+  background-image: url( ../../img/ico/tick-circle.png );
+}
+
+#content #dataimport #current_state.success .info strong
+{
+  color: #080;
+}
+
+#content #dataimport #current_state.aborted
+{
+  background-color: #f3e6e6;
+}
+
+#content #dataimport #current_state.aborted .info
+{
+  background-image: url( ../../img/ico/slash.png );
+}
+
+#content #dataimport #current_state.aborted .info strong
+{
+  color: #800;
+}
+
+#content #dataimport #current_state.failure
+{
+  background-color: #f3e6e6;
+}
+
+#content #dataimport #current_state.failure .info
+{
+  background-image: url( ../../img/ico/cross-button.png );
+}
+
+#content #dataimport #current_state.failure .info strong
+{
+  color: #800;
+}
+
+#content #dataimport #current_state.idle
+{
+  background-color: #e6e6ff;
+}
+
+#content #dataimport #current_state.idle .info
+{
+  background-image: url( ../../img/ico/information.png );
+}
+
+#content #dataimport #error
+{
+  background-color: #f00;
+  background-image: url( ../../img/ico/construction.png );
+  background-position: 10px 50%;
+  color: #fff;
+  font-weight: bold;
+  margin-bottom: 20px;
+  padding: 10px;
+  padding-left: 35px;
+}
+
+#content #dataimport .block h2
+{
+  border-color: #c0c0c0;
+  padding-left: 5px;
+  position: relative;
+}
+
+#content #dataimport .block.hidden h2
+{
+  border-color: #fafafa;
+}
+
+#content #dataimport .block h2 a.toggle
+{
+  background-image: url( ../../img/ico/toggle-small.png );
+  background-position: 0 50%;
+  padding-left: 21px;
+}
+
+#content #dataimport .block.hidden h2 a.toggle
+{
+  background-image: url( ../../img/ico/toggle-small-expand.png );
+}
+
+#content #dataimport #config h2 a.r
+{
+  background-position: 3px 50%;
+  display: block;
+  float: right;
+  margin-left: 10px;
+  padding-left: 24px;
+  padding-right: 3px;
+}
+
+#content #dataimport #config h2 a.reload_config
+{
+  background-image: url( ../../img/ico/arrow-circle.png );
+}
+
+#content #dataimport #config h2 a.reload_config.success
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #dataimport #config h2 a.reload_config.error
+{
+  background-image: url( ../../img/ico/slash.png );
+}
+
+#content #dataimport #config h2 a.debug_mode
+{
+  background-image: url( ../../img/ico/hammer.png );
+  color: #c0c0c0;
+}
+
+#content #dataimport #config.debug_mode h2 a.debug_mode
+{
+  background-color: #ff0;
+  background-image: url( ../../img/ico/hammer-screwdriver.png );
+  color: #333;
+}
+
+#content #dataimport #config .content
+{
+  padding: 5px 2px;
+}
+
+#content #dataimport #dataimport_config .loader
+{
+  background-position: 0 50%;
+  padding-left: 21px;
+}
+
+#content #dataimport #dataimport_config .formatted
+{
+  border: 1px solid #fff;
+  display: block;
+  padding: 2px;
+}
+
+#content #dataimport .debug_mode #dataimport_config .editable
+{
+  display: block;
+}
+
+#content #dataimport #dataimport_config .editable textarea
+{
+  font-family: monospace;
+  height: 120px;
+  min-height: 60px;
+  width: 100%;
+}
+
+#content #dataimport #debug_response em
+{
+  color: #c0c0c0;
+  font-style: normal;
+}

Modified: lucene/dev/trunk/solr/webapp/web/css/angular/menu.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/menu.css?rev=1680118&r1=1680117&r2=1680118&view=diff
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/menu.css (original)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/menu.css Mon May 18 22:35:59 2015
@@ -279,6 +279,7 @@ limitations under the License.
 #core-menu .logging a { background-image: url( ../../img/ico/inbox-document-text.png ); }
 #core-menu .plugins a { background-image: url( ../../img/ico/block.png ); }
 #core-menu .dataimport a { background-image: url( ../../img/ico/document-import.png ); }
+#core-menu .segments a { background-image: url( ../../img/ico/construction.png ); }
 
 
 #content #navigation

Added: lucene/dev/trunk/solr/webapp/web/css/angular/replication.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/replication.css?rev=1680118&view=auto
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/replication.css (added)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/replication.css Mon May 18 22:35:59 2015
@@ -0,0 +1,500 @@
+/*
+
+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.
+
+*/
+
+#content #replication
+{
+  background-image: url( ../../img/div.gif );
+  background-position: 21% 0;
+  background-repeat: repeat-y;
+}
+
+#content #replication #frame
+{
+  float: right;
+  width: 78%;
+}
+
+#content #replication #navigation
+{
+  border-right: 0;
+  float: left;
+  width: 20%;
+}
+
+#content #replication #error
+{
+  background-color: #f00;
+  background-image: url( ../../img/ico/construction.png );
+  background-position: 10px 50%;
+  color: #fff;
+  font-weight: bold;
+  margin-bottom: 20px;
+  padding: 10px;
+  padding-left: 35px;
+}
+
+#content #replication .block
+{
+  border-bottom: 1px solid #c0c0c0;
+  margin-bottom: 20px;
+  padding-bottom: 20px;
+}
+
+#content #replication .block.last
+{
+  border-bottom: 0;
+}
+
+#content #replication .masterOnly,
+#content #replication .slaveOnly
+{
+}
+
+#content #replication.master .masterOnly
+{
+  display: block;
+}
+
+#content #replication.slave .slaveOnly
+{
+  display: block;
+}
+
+#content #replication .replicating
+{
+}
+
+#content #replication.replicating .replicating
+{
+  display: block;
+}
+
+#content #replication #progress
+{
+  padding-bottom: 80px;
+  position: relative;
+}
+
+#content #replication #progress .info
+{
+  padding: 5px;
+}
+
+#content #replication #progress #start
+{
+  margin-left: 100px;
+  border-left: 1px solid #c0c0c0;
+}
+
+#content #replication #progress #bar
+{
+  background-color: #f0f0f0;
+  margin-left: 100px;
+  margin-right: 100px;
+  position: relative;
+}
+
+#content #replication #progress #bar #bar-info,
+#content #replication #progress #bar #eta
+{
+  position: absolute;
+  right: -100px;
+  width: 100px;
+}
+
+#content #replication #progress #bar #bar-info
+{
+  border-left: 1px solid #f0f0f0;
+  margin-top: 30px;
+}
+
+#content #replication #progress #eta .info
+{
+  color: #c0c0c0;
+  height: 30px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+#content #replication #progress #speed
+{
+  color: #c0c0c0;
+  position: absolute;
+  right: 100px;
+  top: 0;
+}
+
+#content #replication #progress #bar #done
+{
+  background-color: #c0c0c0;
+  box-shadow: 5px 5px 10px #c0c0c0;
+  -moz-box-shadow: 5px 5px 10px #c0c0c0;
+  -webkit-box-shadow: 5px 5px 10px #c0c0c0;
+  height: 30px;
+  position: relative;
+}
+
+#content #replication #progress #bar #done .percent
+{
+  font-weight: bold;
+  height: 30px;
+  line-height: 30px;
+  padding-left: 5px;
+  padding-right: 5px;
+  position: absolute;
+  right: 0;
+  text-align: right;
+}
+
+#content #replication #progress #bar #done #done-info
+{
+  border-right: 1px solid #c0c0c0;
+  position: absolute;
+  right: 0;
+  margin-top: 30px;
+  text-align: right;
+  width: 100px;
+}
+
+#content #replication #progress #bar #done #done-info .percent
+{
+  font-weight: bold;
+}
+
+#content #replication .block .label,
+#content #replication #current-file .file,
+#content #replication #current-file .progress,
+#content #replication #iterations .iterations
+{
+  float: left;
+}
+
+#content #replication .block .label
+{
+  width: 100px;
+}
+
+#content #replication .block .label span
+{
+  display: block;
+  padding-left: 21px;
+}
+
+#content #replication #current-file
+{
+  border-top: 1px solid #f0f0f0;
+  margin-top: 10px;
+  padding-top: 10px;
+}
+
+#content #replication #current-file .progress
+{
+  color: #c0c0c0;
+  margin-left: 20px;
+}
+
+#content #replication #iterations .label span
+{
+  background-image: url( ../../img/ico/node-design.png );
+}
+
+#content #replication #iterations .iterations li
+{
+  background-position: 100% 50%;
+  padding-right: 21px;
+}
+
+#content #replication #iterations .iterations.expanded li
+{
+  display: block;
+}
+
+#content #replication #iterations .iterations .latest
+{
+  display: block;
+}
+
+#content #replication #iterations .iterations .replicated
+{
+  color: #80c480;
+}
+
+#content #replication #iterations .iterations ul:hover .replicated,
+#content #replication #iterations .iterations .replicated.latest
+{
+  color: #080;
+}
+
+#content #replication #iterations .iterations .replicated.latest
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #replication #iterations .iterations .failed
+{
+  color: #c48080;
+}
+
+#content #replication #iterations .iterations ul:hover .failed,
+#content #replication #iterations .iterations .failed.latest
+{
+  color: #800;
+}
+
+#content #replication #iterations .iterations .failed.latest
+{
+  background-image: url( ../../img/ico/cross.png );
+}
+
+#content #replication #iterations .iterations a
+{
+  border-top: 1px solid #f0f0f0;
+  margin-top: 2px;
+  padding-top: 2px;
+}
+
+#content #replication #iterations .iterations a span
+{
+  background-position: 0 50%;
+  color: #c0c0c0;
+  padding-left: 21px;
+}
+
+#content #replication #iterations .iterations a span.expand
+{
+  background-image: url( ../../img/ico/chevron-small-expand.png );
+  display: block;
+}
+
+#content #replication #iterations .iterations a span.collapse
+{
+  background-image: url( ../../img/ico/chevron-small.png );
+  display: block;
+}
+
+#content #replication #details table
+{
+  margin-left: 20px;
+  border-collapse: collapse;
+}
+
+#content #replication #details table th
+{
+  text-align: left;
+}
+
+#content #replication.slave #details table .slaveOnly
+{
+  display: table-row;
+}
+
+#content #replication #details table thead th
+{
+  color: #c0c0c0;
+}
+
+#content #replication #details table thead th,
+#content #replication #details table tbody td
+{
+  padding-right: 20px;
+}
+
+#content #replication #details table thead td,
+#content #replication #details table thead th,
+#content #replication #details table tbody th,
+#content #replication #details table tbody td div
+{
+  padding-top: 3px;
+  padding-bottom: 3px;
+}
+
+#content #replication #details table tbody td,
+#content #replication #details table tbody th
+{
+  border-top: 1px solid #f0f0f0;
+}
+
+#content #replication #details table thead td
+{
+  width: 100px;
+}
+
+#content #replication #details table thead td span
+{
+  background-image: url( ../../img/ico/clipboard-list.png );
+  background-position: 0 50%;
+  display: block;
+  padding-left: 21px;
+}
+
+#content #replication #details table tbody th
+{
+  padding-right: 10px;
+  text-align: right;
+  white-space: nowrap;
+}
+
+#content #replication #details table tbody .size
+{
+  text-align: right;
+  white-space: nowrap;
+}
+
+#content #replication #details table tbody .generation div
+{
+  text-align: center;
+}
+
+#content #replication #details table tbody .diff div
+{
+  background-color: #fcfcc9;
+  padding-left: 1px;
+  padding-right: 1px;
+}
+
+#content #replication .settings .label span
+{
+  background-image: url( ../../img/ico/hammer-screwdriver.png );
+}
+
+#content #replication .settings ul,
+#content #replication .settings dl dt,
+#content #replication .settings dl dd
+{
+  float: left;
+}
+
+#content #replication .settings ul li
+{
+  border-top: 1px solid #f0f0f0;
+  padding-top: 3px;
+  padding-top: 3px;
+}
+
+#content #replication .settings ul li:first-child
+{
+  border-top: 0;
+  padding-top: 0;
+}
+
+#content #replication .settings dl dt
+{
+  clear: left;
+  margin-right: 5px;
+  width: 120px;
+}
+
+#content #replication .settings dl .ico
+{
+  background-position: 0 50%;
+  padding-left: 21px;
+}
+
+#content #replication .settings dl .ico.ico-0
+{
+  background-image: url( ../../img/ico/slash.png );
+}
+
+#content #replication .settings dl .ico.ico-1
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #replication .timer
+{
+  box-shadow: 5px 5px 10px #c0c0c0;
+  -moz-box-shadow: 5px 5px 10px #c0c0c0;
+  -webkit-box-shadow: 5px 5px 10px #c0c0c0;
+  margin-bottom: 20px;
+  padding: 10px;
+}
+
+#content #replication .timer p,
+#content #replication .timer small
+{
+  padding-left: 21px;
+}
+
+#content #replication .timer p
+{
+  background-image: url( ../../img/ico/clock-select-remain.png );
+  background-position: 0 50%;
+}
+
+#content #replication .timer p .approx
+{
+  color: #c0c0c0;
+  margin-right: 1px;
+}
+
+#content #replication .timer p .tick
+{
+  font-weight: bold;
+}
+
+#content #replication .timer small
+{
+  color: #c0c0c0;
+}
+
+#content #replication #navigation button
+{
+  display: block;
+  margin-bottom: 10px;
+}
+
+#content #replication #navigation button.optional
+{
+}
+
+#content #replication #navigation .replicate-now span
+{
+  background-image: url( ../../img/ico/document-convert.png );
+}
+
+#content #replication #navigation .abort-replication span
+{
+  background-image: url( ../../img/ico/hand.png );
+}
+
+#content #replication #navigation .disable-polling span
+{
+  background-image: url( ../../img/ico/cross.png );
+}
+
+#content #replication #navigation .enable-polling span
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #replication #navigation .disable-replication span
+{
+  background-image: url( ../../img/ico/cross.png );
+}
+
+#content #replication #navigation .enable-replication span
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #replication #navigation .refresh-status span
+{
+  background-image: url( ../../img/ico/arrow-circle.png );
+}

Added: lucene/dev/trunk/solr/webapp/web/css/angular/schema-browser.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/schema-browser.css?rev=1680118&view=auto
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/schema-browser.css (added)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/schema-browser.css Mon May 18 22:35:59 2015
@@ -0,0 +1,567 @@
+/*
+
+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.
+
+*/
+
+#content #schema-browser .loader
+{
+  background-position: 0 50%;
+  padding-left: 21px;   
+}
+
+#content #schema-browser.loaded
+{
+  background-image: url( ../../img/div.gif );
+  background-position: 21% 0;
+  background-repeat: repeat-y;
+}
+
+#content #schema-browser #data
+{
+  float: right;
+  width: 78%;
+}
+
+#content #schema-browser #related
+{
+  float: left;
+  width: 20%;
+}
+
+#content #schema-browser #related select
+{
+  width: 100%;
+}
+
+#content #schema-browser #related select optgroup
+{
+  font-style: normal;
+  padding: 5px;
+}
+
+#content #schema-browser #related select option
+{
+  padding-left: 10px;
+}
+
+#content #schema-browser #related #f-df-t
+{
+  border-bottom: 1px solid #f0f0f0;
+  padding-bottom: 15px;
+}
+
+#content #schema-browser #related .ukf-dsf dt
+{
+}
+
+#content #schema-browser #related dl
+{
+  margin-top: 15px;
+}
+
+#content #schema-browser #related dl dt,
+#content #schema-browser #related dl dd a
+{
+  color: #c0c0c0;
+}
+
+#content #schema-browser #related dl dt
+{
+  font-weight: bold;
+  margin-top: 5px;
+}
+
+#content #schema-browser #related dl dd a
+{
+  display: block;
+  padding-left: 10px;
+}
+
+#content #schema-browser #related dl dd a:hover
+{
+  background-color: #f8f8f8;
+}
+
+#content #schema-browser #related .field .field,
+#content #schema-browser #related .field .field a,
+#content #schema-browser #related .dynamic-field .dynamic-field,
+#content #schema-browser #related .dynamic-field .dynamic-field a,
+#content #schema-browser #related .type .type,
+#content #schema-browser #related .type .type a,
+#content #schema-browser #related .active,
+#content #schema-browser #related .active a
+{
+  color: #333;
+}
+
+#content #schema-browser #related .copyfield,
+#content #schema-browser #related .copyfield a
+{
+  color: #666;
+}
+
+#content #schema-browser #data
+{
+}
+
+#content #schema-browser #data #index dt
+{
+  float: left;
+  margin-right: 5px;
+  width: 150px;
+}
+
+#content #schema-browser #data #field .field-options
+{
+  margin-bottom: 10px;
+}
+
+#content #schema-browser #data #field .field-options .head h2
+{
+  padding-left: 5px;
+}
+
+#content #schema-browser #data #field .partial
+{
+}
+
+#content #schema-browser #data #field .partial p
+{
+  background-image: url( ../../img/ico/exclamation-button.png );
+  background-position: 0 50%;
+  padding-left: 21px;
+}
+
+#content #schema-browser #data #field .field-options .options dt,
+#content #schema-browser #data #field .field-options .options dd
+{
+  float: left;
+}
+
+#content #schema-browser #data #field .field-options .options dt
+{
+  clear: left;
+  margin-right: 5px;
+  width: 100px;
+}
+
+#content #schema-browser #data #field .field-options .flags
+{
+  margin-top: 10px;
+  margin-bottom: 20px;
+}
+
+#content #schema-browser #data #field .field-options .flags thead td
+{
+  color: #c0c0c0;
+  padding-right: 5px;
+  width: 100px;
+}
+
+#content #schema-browser #data #field .field-options .flags tbody td,
+#content #schema-browser #data #field .field-options .flags th
+{
+  padding: 2px 5px;
+}
+
+#content #schema-browser #data #field .field-options .flags thead td,
+#content #schema-browser #data #field .field-options .flags tbody th
+{
+  padding-left: 0;
+}
+
+#content #schema-browser #data #field .field-options .flags thead th,
+#content #schema-browser #data #field .field-options .flags tbody td
+{
+  border-left: 1px solid #f0f0f0;
+}
+
+#content #schema-browser #data #field .field-options .flags tbody th,
+#content #schema-browser #data #field .field-options .flags tbody td
+{
+  border-top: 1px solid #f0f0f0;
+}
+
+#content #schema-browser #data #field .field-options .flags tbody .check
+{
+  background-color: #fafdfa;
+  background-image: url( ../../img/ico/tick.png );
+  background-position: 50% 50%;
+  text-align: center;
+}
+
+#content #schema-browser #data #field .field-options .flags tbody .check span
+{
+}
+
+#content #schema-browser #data #field .field-options .flags tbody .text
+{
+  color: #c0c0c0;
+}
+
+#content #schema-browser #data #field .field-options .analyzer,
+#content #schema-browser #data #field .field-options .analyzer li,
+#content #schema-browser #data #field .field-options .analyzer ul,
+#content #schema-browser #data #field .field-options .analyzer ul li
+{
+}
+
+#content #schema-browser #data #field .field-options .analyzer p,
+#content #schema-browser #data #field .field-options .analyzer dl
+{
+  float: left;
+}
+
+#content #schema-browser #data #field .field-options .analyzer p
+{
+  margin-right: 5px;
+  text-align: right;
+  width: 125px;
+  white-space: pre;
+}
+
+#content #schema-browser #data #field .field-options .analyzer p a
+{
+  cursor: auto;
+}
+
+#content #schema-browser #data #field .field-options .analyzer p a.analysis
+{
+  cursor: pointer;
+  display: block;
+}
+
+#content #schema-browser #data #field .field-options .analyzer p a.analysis span
+{
+  background-image: url( ../../img/ico/question-white.png );
+  background-position: 0 50%;
+  padding-left: 21px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer p a.analysis:hover span
+{
+  background-image: url( ../../img/ico/question.png );
+  color: #008;
+}
+
+#content #schema-browser #data #field .field-options .analyzer a
+{
+  cursor: auto;
+}
+
+#content #schema-browser #data #field .field-options .analyzer .toggle
+{
+  background-image: url( ../../img/ico/chevron-small-expand.png );
+  background-position: 100% 50%;
+  cursor: pointer;
+  display: block;
+  padding-right: 21px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer .open .toggle
+{
+  background-image: url( ../../img/ico/chevron-small.png );
+}
+
+#content #schema-browser #data #field .field-options .analyzer li
+{
+  border-top: 1px solid #f0f0f0;
+  margin-top: 10px;
+  padding-top: 10px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul
+{
+  clear: left;
+  margin-left: 55px;
+  padding-top: 5px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer .open ul
+{
+  display: block;
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul li
+{
+  border-top: 1px solid #f8f8f8;
+  margin-top: 5px;
+  padding-top: 5px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul p
+{
+  color: #999;
+  margin-right: 5px;
+  text-align: right;
+  width: 70px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul dd
+{
+  margin-left: 20px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul dd
+{
+  background-image: url( ../../img/ico/document-list.png );
+  background-position: 0 50%;
+  color: #c0c0c0;
+  padding-left: 21px;
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul dd.ico-0
+{
+  background-image: url( ../../img/ico/slash.png );
+}
+
+#content #schema-browser #data #field .field-options .analyzer ul dd.ico-1
+{
+  background-image: url( ../../img/ico/tick.png );
+}
+
+#content #schema-browser #data #field .head
+{
+  margin-bottom: 5px;
+}
+
+#content #schema-browser #data #field .terminfo-holder
+{
+  border-top: 1px solid #c0c0c0;
+  padding-top: 10px;
+}
+
+#content #schema-browser #data #field .terminfo-holder .trigger
+{
+  float: left;
+  width: 140px;
+}
+
+#content #schema-browser #data #field .terminfo-holder .trigger button span
+{
+  background-image: url( ../../img/ico/information.png );
+}
+
+#content #schema-browser #data #field .terminfo-holder .status
+{
+  border-left: 1px solid #f0f0f0;
+  float: left;
+  padding-left: 20px;
+  padding-right: 20px;
+}
+
+#content #schema-browser #data #field .terminfo-holder.disabled .trigger button span
+{
+  background-image: url( ../../img/ico/prohibition.png );
+}
+
+#content #schema-browser #data #field .terminfo-holder.disabled .status
+{
+  display: block;
+}
+
+#content #schema-browser #data #field .terminfo-holder .trigger .autoload
+{
+}
+
+#content #schema-browser #data #field .terminfo-holder.loaded .trigger .autoload
+{
+  background-image: url( ../../img/ico/ui-check-box-uncheck.png );
+  background-position: 0 50%;
+  color: #c0c0c0;
+  display: block;
+  margin-top: 10px;
+  padding-left: 21px;
+}
+
+#content #schema-browser #data #field .terminfo-holder .trigger .autoload:hover
+{
+  color: #008;
+}
+
+#content #schema-browser #data #field .terminfo-holder .trigger .autoload.on
+{
+  background-image: url( ../../img/ico/ui-check-box.png );
+  color: #333;
+}
+
+#content #schema-browser #data #field .topterms-holder,
+#content #schema-browser #data #field .histogram-holder
+{
+  border-left: 1px solid #f0f0f0;
+  float: left;
+  padding-left: 20px;
+  padding-right: 20px;
+}
+
+#content #schema-browser #data #field .topterms-holder .head input
+{
+  height: 18px;
+  line-height: 16px;
+  text-align: right;
+  width: 30px;
+}
+
+#content #schema-browser #data #field .topterms-holder .head .max-holder
+{
+  color: #c0c0c0;
+}
+
+#content #schema-browser #data #field .topterms-holder .head .max-holder:hover .max
+{
+  color: #008;
+}
+
+#content #schema-browser #data #field .topterms-holder .head #query_link
+{
+  background-image: url( ../../img/ico/question-white.png );
+  background-position: 0 50%;
+  color: #c0c0c0;
+  padding-left: 21px;
+  margin-left: 5px;
+}
+
+#content #schema-browser #data #field .topterms-holder .head #query_link:hover
+{
+  background-image: url( ../../img/ico/question.png );
+}
+
+
+#content #schema-browser #data #field .topterms-holder .head #query_link span
+{
+  visibility: hidden;
+}
+
+#content #schema-browser #data #field .topterms-holder .head #query_link:hover span
+{
+  visibility: visible;
+}
+
+#content #schema-browser .topterms-holder li
+{
+  border-top: 1px solid  #999;
+  margin-bottom: 5px;
+}
+
+/* possible overwrite with inline style */
+#content #schema-browser .topterms-holder li p
+{
+  background-color:  #999;
+  color: #fff;
+  float: left;
+}
+
+#content #schema-browser .topterms-holder li p span
+{
+  display: block;
+  padding-right: 2px;
+  text-align: right;
+}
+
+/* possible overwrite with inline style */
+#content #schema-browser .topterms-holder li ul
+{
+  margin-left: 30px;
+}
+
+#content #schema-browser .topterms-holder li li
+{
+  border-top: 0;
+  margin-bottom: 0;
+  white-space: nowrap;
+}
+
+#content #schema-browser .topterms-holder li li.odd
+{
+  background-color: #f0f0f0;
+}
+
+#content #schema-browser .topterms-holder li li a
+{
+  display: block;
+  padding-left: 2px;
+  padding-right: 2px;
+}
+
+#content #schema-browser .topterms-holder li li a:hover
+{
+  background-color: #c0c0c0;
+}
+
+#content #schema-browser #data #field .histogram-holder ul
+{
+  margin-left: 25px;
+}
+
+#content #schema-browser #data #field .histogram-holder li
+{
+  margin-bottom: 2px;
+  position: relative;
+  width: 150px;
+}
+
+#content #schema-browser #data #field .histogram-holder li.odd
+{
+  background-color: #f0f0f0;
+}
+
+#content #schema-browser #data #field .histogram-holder li dl,
+#content #schema-browser #data #field .histogram-holder li dt
+{
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+
+#content #schema-browser #data #field .histogram-holder li dl
+{
+  background-color: #c0c0c0;
+  min-width: 1px;
+}
+
+#content #schema-browser #data #field .histogram-holder li dt
+{
+  color: #a0a0a0;
+  position: absolute;
+  overflow: hidden;
+  left: -25px;
+  top: 0px;
+}
+
+#content #schema-browser #data #field .histogram-holder li dt span
+{
+  display: block;
+  padding-right: 4px;
+  text-align: right;
+}
+
+#content #schema-browser #data #field .histogram-holder li dd
+{
+  clear: left;
+  float: left;
+  margin-left: 2px;
+  white-space: nowrap;
+}
+
+#content #schema-browser #data #field .histogram-holder li:hover dl
+{
+  background-color: #b0b0b0;
+}
+
+#content #schema-browser #data #field .histogram-holder li:hover dt
+{
+  color: #333;
+}

Added: lucene/dev/trunk/solr/webapp/web/css/angular/segments.css
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/css/angular/segments.css?rev=1680118&view=auto
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/css/angular/segments.css (added)
+++ lucene/dev/trunk/solr/webapp/web/css/angular/segments.css Mon May 18 22:35:59 2015
@@ -0,0 +1,173 @@
+/*
+
+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.
+
+*/
+
+#content #segments .loader
+{
+  background-position: 0 50%;
+  padding-left: 21px;
+}
+
+#content #segments .reload
+{
+  background-image: url( ../../img/ico/arrow-circle.png );
+  background-position: 50% 50%;
+  display: block;
+  height: 30px;
+  position: absolute;
+  right: 10px;
+  top: 10px;
+  width: 30px; 
+}
+
+#content #segments .reload.loader
+{
+  padding-left: 0;
+}
+
+#content #segments .reload span
+{
+  display: none;
+}
+
+#content #segments #result
+{   
+  width: 77%;
+}
+
+#content #segments #result #response
+{
+	margin-left: 25px;
+}
+
+#content #segments .segments-holder ul {
+    margin-left: 25px;
+}
+#content #segments .segments-holder li {
+    margin-bottom: 2px;
+    position: relative;
+    width: 100%;
+}
+
+#content #segments .segments-holder li .tooltip {
+	display: none;
+    background: #C8C8C8;
+    position: absolute;
+    z-index: 1000;
+    width:220px;
+    height:120px;
+    margin-left: 100%;
+    opacity: .8;
+    padding: 5px;
+    border: 1px solid;
+    border-radius: 5px;
+}
+
+#content #segments .segments-holder li .tooltip .label {
+	float: left;
+	width: 20%;	
+	opacity: 1;
+}
+
+#content #segments .segments-holder li:hover .tooltip {
+	display:block;	
+}
+
+#content #segments .segments-holder li dl, 
+#content #segments .segments-holder li dt {
+    padding-bottom: 1px;
+    padding-top: 1px;
+}
+#content #segments .segments-holder li dl {
+    min-width: 1px;
+}
+#content #segments .segments-holder li dt {
+    color: #a0a0a0;
+    left: -45px;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+}
+#content #segments .segments-holder li dt div {
+    display: block;
+    padding-right: 4px;
+    text-align: right;
+}
+#content #segments .segments-holder li dd {
+    clear: left;
+    float: left;
+    margin-left: 2px;
+    white-space: nowrap;
+    width: 100%;
+}
+
+#content #segments .segments-holder li dd div.deleted {
+    background-color: #808080;    
+    padding-left: 5px;    
+}
+
+#content #segments .segments-holder li dd div.live {
+	background-color: #DDDDDD;
+	float: left;	
+}
+
+#content #segments .segments-holder li dd div.start {
+	float: left;
+	width: 20%;
+}
+
+#content #segments .segments-holder li dd div.end {
+	text-align: right;
+}
+
+.merge-candidate {
+	background-color: #FFC9F9 !important;
+}
+
+#content #segments .segments-holder li dd div.w5 {
+	width: 20%;
+	float: left;
+}
+
+#content #segments #auto-refresh {
+  margin-top: 4px;
+  background-position: 50% 50%;
+  display: block;
+  height: 30px;
+  position: absolute;
+  right: 50px;
+  top: 10px;
+}
+
+#content #segments #auto-refresh a {
+  background-image: url( ../../img/ico/ui-check-box-uncheck.png );
+  background-position: 0 50%;
+  color: #c0c0c0;
+  display: block;
+  padding-left: 21px;
+}
+
+#content #segments #auto-refresh a.on,
+#content #segments #auto-refresh a:hover {
+  color: #333;
+}
+
+#content #segments #auto-refresh a.on {
+  background-image: url( ../../img/ico/ui-check-box.png );
+}
+

Modified: lucene/dev/trunk/solr/webapp/web/index.html
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/index.html?rev=1680118&r1=1680117&r2=1680118&view=diff
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/index.html (original)
+++ lucene/dev/trunk/solr/webapp/web/index.html Mon May 18 22:35:59 2015
@@ -28,7 +28,7 @@ limitations under the License.
   <link rel="stylesheet" type="text/css" href="css/angular/cloud.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/cores.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/styles/dashboard.css?_=${version}">
-  <link rel="stylesheet" type="text/css" href="css/styles/dataimport.css?_=${version}">
+  <link rel="stylesheet" type="text/css" href="css/angular/dataimport.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/files.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/index.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/styles/java-properties.css?_=${version}">
@@ -37,8 +37,9 @@ limitations under the License.
   <link rel="stylesheet" type="text/css" href="css/angular/plugins.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/documents.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/query.css?_=${version}">
-  <link rel="stylesheet" type="text/css" href="css/styles/replication.css?_=${version}">
-  <link rel="stylesheet" type="text/css" href="css/styles/schema-browser.css?_=${version}">
+  <link rel="stylesheet" type="text/css" href="css/angular/replication.css?_=${version}">
+  <link rel="stylesheet" type="text/css" href="css/angular/schema-browser.css?_=${version}">
+  <link rel="stylesheet" type="text/css" href="css/angular/segments.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/threads.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/angular/chosen.css?_=${version}">
 
@@ -53,6 +54,7 @@ limitations under the License.
   <script src="libs/angular-cookies.min.js"></script>
   <script src="libs/ngtimeago.js"></script>
   <script src="libs/highlight.js"></script>
+  <script src="libs/d3.js"></script>
   <script src="js/angular/app.js"></script>
   <script src="js/angular/services.js"></script>
   <script src="js/angular/controllers/index.js"></script>
@@ -63,10 +65,14 @@ limitations under the License.
   <script src="js/angular/controllers/java-properties.js"></script>
   <script src="js/angular/controllers/core-overview.js"></script>
   <script src="js/angular/controllers/analysis.js"></script>
+  <script src="js/angular/controllers/dataimport.js"></script>
   <script src="js/angular/controllers/documents.js"></script>
   <script src="js/angular/controllers/files.js"></script>
   <script src="js/angular/controllers/query.js"></script>
   <script src="js/angular/controllers/plugins.js"></script>
+  <script src="js/angular/controllers/replication.js"></script>
+  <script src="js/angular/controllers/schema-browser.js"></script>
+  <script src="js/angular/controllers/segments.js"></script>
 
 </head>
 <body ng-controller="MainController">
@@ -91,9 +97,7 @@ limitations under the License.
 
       </div>
 
-      <div id="loading" class="header-message" loading-status-message>
-        Loading...
-      </div>
+      <div id="loading" class="loader universal-loader" loading-status-message>&nbsp;</div>
 
       <div id="connection-box" connection-message>
         <div id="connection-status-modal">
@@ -134,12 +138,12 @@ limitations under the License.
               </ul>
             </li>
 
-            <li id="cloud" class="global optional" ng-show="isCloudEnabled" ng-class="{active:page=='cloud'}"><p><a href="#/~cloud">Cloud</a></p>
+            <li id="cloud" class="global optional" ng-show="isCloudEnabled" ng-class="{active:showingCloud}"><p><a href="#/~cloud">Cloud</a></p>
               <ul ng-show="showingCloud">
                 <li class="tree" ng-class="{active:page=='cloud-tree'}"><a href="#/~cloud?view=tree">Tree</a></li>
                 <li class="graph" ng-class="{active:page=='cloud-graph'}"><a href="#/~cloud">Graph</a></li>
                 <li class="rgraph" ng-class="{active:page=='cloud-rgraph'}"><a href="#/~cloud?view=rgraph">Graph (Radial)</a></li>
-                <li class="dump" ng-class="{active:page=='cloud-dump'}"><a href="#/~cloud">Dump</a></li>
+                <li class="dump" ng-class="{active:page=='cloud-dump'}"><a ng-click="dumpCloud()">Dump</a></li>
               </ul>
             </li>
 
@@ -175,6 +179,7 @@ limitations under the License.
               <li class="query" ng-class="{active:page=='query'}"><a href="#/{{currentCore.name}}/query"><span>Query</span></a></li>
               <li class="replication" ng-class="{active:page=='replication'}"><a href="#/{{currentCore.name}}/replication"><span>Replication</span></a></li>
               <li class="schema-browser" ng-class="{active:page=='schema-browser'}"><a href="#/{{currentCore.name}}/schema-browser"><span>Schema Browser</span></a></li>
+              <li class="segments" ng-class="{active:page=='segments'}"><a href="#/{{currentCore.name}}/segments"><span>Segments info</span></a></li>
 	    </ul>
           </div>
 

Modified: lucene/dev/trunk/solr/webapp/web/js/angular/app.js
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/js/angular/app.js?rev=1680118&r1=1680117&r2=1680118&view=diff
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/js/angular/app.js (original)
+++ lucene/dev/trunk/solr/webapp/web/js/angular/app.js Mon May 18 22:35:59 2015
@@ -67,6 +67,14 @@ solrAdminApp.config([
         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'
@@ -89,6 +97,26 @@ solrAdminApp.config([
         templateUrl: 'partials/query.html',
         controller: 'QueryController'
       }).
+      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-browser', {
+        templateUrl: 'partials/schema-browser.html',
+        controller: 'SchemaBrowserController'
+      }).
+      when('/:core/segments', {
+        templateUrl: 'partials/segments.html',
+        controller: 'SegmentsController'
+      }).
       otherwise({
         redirectTo: '/'
       });
@@ -110,6 +138,59 @@ solrAdminApp.config([
     }
   };
 })
+.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];
+        }
+
+        var result= ( input || 0 ).toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+            sep[ browser.locale ] || sep[ browser.language ] || sep['_']);
+        console.log(result);
+        return result;
+    };
+})
 .filter('orderObjectBy', function() {
   return function(items, field, reverse) {
     var filtered = [];
@@ -177,7 +258,7 @@ solrAdminApp.config([
       $rootScope.$broadcast('loadingStatusActive');
     }
     activeRequests++;
-    config.timeout = 1000;
+    config.timeout = 10000;
     return config || $q.when(config);
   };
 
@@ -238,24 +319,29 @@ solrAdminApp.config([
     };
 });
 
-var solrAdminControllers = angular.module('solrAdminControllers', []);
-
-solrAdminApp.controller('MainController', function($scope, $routeParams, $rootScope, $location, Cores, Ping) {
+solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $location, Cores, System, Ping) {
   $rootScope.hideException = function() {delete $rootScope.exception};
   $scope.refresh = function() {
     Cores.list(function(data) {
-     var cores = [];
-       for (key in data.status) {
-        cores.push(data.status[key]);
+      $scope.cores = [];
+      var currentCoreName = $route.current.params.core;
+      for (key in data.status) {
+        var core = data.status[key];
+        $scope.cores.push(core);
+        if (core.name == currentCoreName) {
+            $scope.currentCore = core;
+        }
       }
       $scope.cores = cores;
     });
+    System.get(function(data) {
+      $scope.isCloudEnabledCloud = data.mode.match( /solrcloud/i )
+    });
   };
   $scope.refresh();
 
   $scope.resetMenu = function(page) {
     $scope.showingLogging = page.lastIndexOf("logging", 0) === 0;
-    $scope.isCloudEnabled = true;
     $scope.showingCloud = page.lastIndexOf("cloud", 0) === 0;
     $scope.page = page;
   };
@@ -274,27 +360,93 @@ solrAdminApp.controller('MainController'
 
 
 
-/* THE BELOW CODE IS TAKEN FROM js/scripts/app.js, AND STILL REQUIRES INTEGRATING
+(function(window, angular, undefined) {
+  'use strict';
 
-SolrDate = function( date )
-{
-  // ["Sat Mar 03 11:00:00 CET 2012", "Sat", "Mar", "03", "11:00:00", "CET", "2012"]
-  var parts = date.match( /^(\w+)\s+(\w+)\s+(\d+)\s+(\d+\:\d+\:\d+)\s+(\w+)\s+(\d+)$/ );
+  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)
+              }));
+            });
 
-  // "Sat Mar 03 2012 10:37:33"
-  return new Date( parts[1] + ' ' + parts[2] + ' ' + parts[3] + ' ' + parts[6] + ' ' + parts[4] );
-}
+            return;
+          }
 
-// @todo clear timeouts
+          // 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);
 
-    this.bind
-    (
-      'error',
-      function( message, original_error )
-      {
-        alert( original_error.message );
-      }
-    );
+
+/* THE BELOW CODE IS TAKEN FROM js/scripts/app.js, AND STILL REQUIRES INTEGRATING
+
+
+// @todo clear timeouts
 
     // activate_core
     this.before
@@ -362,12 +514,6 @@ var solr_admin = function( app_config )
 
   this.core_regex_base = '^#\\/([\\w\\d-\\.]+)';
 
-  browser = {
-    locale : null,
-    language : null,
-    country : null
-  };
-
   show_global_error = function( error )
   {
     var main = $( '#main' );
@@ -454,8 +600,6 @@ var solr_admin = function( app_config )
     }
 
     var core_selector = $( '#core-selector' );
-    core_selector.find( '#has-cores' ).toggle( has_cores );
-    core_selector.find( '#has-no-cores' ).toggle( !has_cores );
 
     if( has_cores )
     {
@@ -468,70 +612,10 @@ var solr_admin = function( app_config )
       cores_element.find( '.chzn-drop' )
         .css( 'width', ( selector_width - 2 ) + 'px' );
     }
-
-    this.check_for_init_failures( cores );
   };
 
-  this.remove_init_failures = function remove_init_failures()
-  {
-    $( '#init-failures' )
-      .hide()
-      .find( 'ul' )
-        .empty();
-  }
-
-  this.check_for_init_failures = function check_for_init_failures( cores )
-  {
-    if( !cores.initFailures )
-    {
-      this.remove_init_failures();
-      return false;
-    }
-
-    var failures = [];
-    for( var core_name in cores.initFailures )
-    {
-      failures.push
-      (
-        '<li>' +
-          '<strong>' + core_name.esc() + ':</strong>' + "\n" +
-          cores.initFailures[core_name].esc() + "\n" +
-        '</li>'
-      );
-    }
-
-    if( 0 === failures.length )
-    {
-      this.remove_init_failures();
-      return false;
-    }
-
-    $( '#init-failures' )
-      .show()
-      .find( 'ul' )
-        .html( failures.join( "\n" ) );
-  }
-
   this.run = function()
   {
-    var navigator_language = navigator.userLanguage || navigator.language;
-    var language_match = navigator_language.match( /^(\w{2})([-_](\w{2}))?$/ );
-    if( language_match )
-    {
-      if( language_match[1] )
-      {
-        browser.language = language_match[1].toLowerCase();
-      }
-      if( language_match[3] )
-      {
-        browser.country = language_match[3].toUpperCase();
-      }
-      if( language_match[1] && language_match[3] )
-      {
-        browser.locale = browser.language + '_' + browser.country
-      }
-    }
-
     $.ajax
     (
       {
@@ -619,113 +703,10 @@ var solr_admin = function( app_config )
                   '<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />'.esc() +
                   '</code></pre></div>'
                 );
-              },
-              complete : function()
-              {
-                loader.hide( this );
-              }
-            }
-          );
-        },
-        error : function()
-        {
-        },
-        complete : function()
-        {
-        }
-      }
-    );
-  };
-
-  this.convert_duration_to_seconds = function convert_duration_to_seconds( str )
-  {
-    var seconds = 0;
-    var arr = new String( str || '' ).split( '.' );
-    var parts = arr[0].split( ':' ).reverse();
-    var parts_count = parts.length;
-
-    for( var i = 0; i < parts_count; i++ )
-    {
-      seconds += ( parseInt( parts[i], 10 ) || 0 ) * Math.pow( 60, i );
-    }
-
-    // treat more or equal than .5 as additional second
-    if( arr[1] && 5 <= parseInt( arr[1][0], 10 ) )
-    {
-      seconds++;
-    }
-
-    return seconds;
-  };
-
-  this.convert_seconds_to_readable_time = function convert_seconds_to_readable_time( seconds )
-  {
-    seconds = parseInt( seconds || 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( ' ' );
-  };
-
-  this.format_json = function format_json( json_str )
-  {
-    if( JSON.stringify && JSON.parse )
-    {
-      json_str = JSON.stringify( JSON.parse( json_str ), undefined, 2 );
-    }
-
-    return json_str.esc();
-  };
-
-  this.format_number = function format_number( number )
-  {
-    var sep = {
-      'de_CH' : '\'',
-      'de' : '.',
-      'en' : ',',
-      'es' : '.',
-      'it' : '.',
-      'ja' : ',',
-      'sv' : ' ',
-      'tr' : '.',
-      '_' : '' // fallback
-    };
-
-    return ( number || 0 ).toString().replace
-    (
-      /\B(?=(\d{3})+(?!\d))/g,
-      sep[ browser.locale ] || sep[ browser.language ] || sep['_']
-    );
   };
 
   check_fixed_menu = function check_fixed_menu()
   {
     $( '#wrapper' ).toggleClass( 'scroll', $( window ).height() < $( '#menu-wrapper' ).height() + $( '#header' ).height() + 40 );
   }
-
-};
-
-
-
-$.ajaxSetup( { cache: false } );
-var app = new solr_admin( app_config );
 */

Added: lucene/dev/trunk/solr/webapp/web/js/angular/controllers/dataimport.js
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/js/angular/controllers/dataimport.js?rev=1680118&view=auto
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/js/angular/controllers/dataimport.js (added)
+++ lucene/dev/trunk/solr/webapp/web/js/angular/controllers/dataimport.js Mon May 18 22:35:59 2015
@@ -0,0 +1,275 @@
+/*
+ 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 dataimport_timeout = 2000;
+
+solrAdminApp.controller('DataImportController',
+    function($scope, $rootScope, $routeParams, $location, $timeout, $interval, $cookies, Mbeans, DataImport) {
+        $scope.resetMenu("dataimport");
+
+        $scope.refresh = function () {
+            Mbeans.info({core: $routeParams.core, cat: 'QUERYHANDLER'}, function (data) {
+                var mbeans = data['solr-mbeans'][1];
+                $scope.handlers = [];
+                for (var key in mbeans) {
+                    if (mbeans[key]['class'] !== key && mbeans[key]['class'] === 'org.apache.solr.handler.dataimport.DataImportHandler') {
+                        $scope.handlers.push(key);
+                    }
+                }
+                $scope.hasHandlers = $scope.handlers.length > 0;
+
+                if (!$routeParams.handler) {
+                    $location.path("/" + $routeParams.core + "/dataimport/" + $scope.handlers[0]);
+                } else {
+                    $scope.currentHandler = $routeParams.handler;
+                }
+            });
+
+            DataImport.config({core: $routeParams.core}, function (data) {
+                $scope.config = data.config;
+                $scope.entities = [];
+                var xml = $.parseXML($scope.config);
+                $('document > entity', xml).each(function (i, element) {
+                    $scope.entities.push($(element).attr('name'));
+                });
+            });
+
+            $scope.lastUpdate = "unknown";
+            $scope.lastUpdateUTC = "";
+
+            $scope.refreshStatus();
+        };
+
+        $scope.toggleDebug = function () {
+            $scope.isDebugMode = !$scope.isDebugMode;
+            $scope.showConfiguration = true;
+        }
+
+        $scope.toggleConfiguration = function () {
+            $scope.showConfiguration = !$scope.showConfiguration;
+        }
+
+        $scope.toggleRawStatus = function () {
+            $scope.showRawStatus = !$scope.showRawStatus;
+        }
+
+        $scope.toggleRawDebug = function () {
+            $scope.showRawDebug = !$scope.showRawDebug;
+        }
+
+        $scope.reload = function () {
+            DataImport.reload({core: $routeParams.core}, function () {
+                $scope.reloaded = true;
+                $timeout(function () {
+                    $scope.reloaded = false;
+                }, 5000);
+                $scope.refresh();
+            });
+        }
+
+        $scope.form = {
+            command: "full-import",
+            verbose: false,
+            clean: true,
+            commit: true,
+            optimize: false,
+            showDebug: false,
+            custom: "",
+            core: $routeParams.core
+        };
+
+        $scope.submit = function () {
+            var params = {};
+            for (var key in $scope.form) {
+                params[key] = $scope.form[key];
+            }
+            if (params.custom.length) {
+                var customParams = $scope.form.custom.split("&");
+                for (var i in customParams) {
+                    var parts = customParams[i].split("=");
+                    params[parts[0]] = parts[1];
+                }
+            }
+            delete params.custom;
+
+            if (params.isDebugMode) {
+                params.dataConfig = $scope.rawConfig;
+            }
+            delete params.showDebug;
+            params.core = $routeParams.core;
+
+            DataImport.post(params, function (data) {
+                $scope.rawResponse = JSON.stringify(data, null, 2);
+                $scope.refreshStatus();
+            });
+        };
+
+        $scope.abort = function () {
+            $scope.isAborting = true;
+            DataImport.abort({core: $routeParams.core}, function () {
+                $timeout(function () {
+                    $scope.isAborting = false;
+                    $scope.refreshStatus();
+                }, 4000);
+            });
+        }
+
+        $scope.refreshStatus = function () {
+
+            console.log("Refresh Status");
+
+            $scope.isStatusLoading = true;
+            DataImport.status({core: $routeParams.core}, function (data) {
+
+                var now = new Date();
+                $scope.lastUpdate = now.toTimeString().split(' ').shift();
+                $scope.lastUpdateUTC = now.toUTCString();
+                var messages = data.statusMessages;
+                var messagesCount = 0;
+                for( var key in messages ) { messagesCount++; }
+
+                if (data.status == 'busy') {
+                    $scope.status = "indexing";
+
+                    $scope.timeElapsed = data.statusMessages['Time Elapsed'];
+                    $scope.elapsedSeconds = parseSeconds($scope.timeElapsed);
+
+                    var info = $scope.timeElapsed ? 'Indexing since ' + $scope.timeElapsed : 'Indexing ...';
+                    $scope.info = showInfo(messages, true, info, $scope.elapsedSeconds);
+
+                } else if (messages.RolledBack) {
+                    $scope.status = "failure";
+                    $scope.info = showInfo(messages, true);
+                } else if (messages.Aborted) {
+                    $scope.status = "aborted";
+                    $scope.info = showInfo(messages, true, 'Aborting current Import ...');
+                } else if (data.status == "idle" && messagesCount != 0) {
+                    $scope.status = "success";
+                    $scope.info = showInfo(messages, true);
+                } else {
+                    $scope.status = "idle";
+                    $scope.info = showInfo(messages, false, 'No information available (idle)');
+                }
+
+                delete data.$promise;
+                delete data.$resolved;
+
+                $scope.rawStatus = JSON.stringify(data, null, 2);
+
+                $scope.isStatusLoading = false;
+                $scope.statusUpdated = true;
+                $timeout(function () {
+                    $scope.statusUpdated = false;
+                }, dataimport_timeout / 2);
+            });
+        };
+
+        $scope.updateAutoRefresh = function () {
+            $scope.autorefresh = !$scope.autorefresh;
+            $cookies.dataimport_autorefresh = $scope.autorefresh ? true : null;
+            if ($scope.autorefresh) {
+                $scope.refreshTimeout = $interval($scope.refreshStatus, dataimport_timeout);
+            } else if ($scope.refreshTimeout) {
+                $interval.cancel($scope.refreshTimeout);
+            }
+            $scope.refreshStatus();
+        };
+
+        $scope.refresh();
+
+});
+
+var showInfo = function (messages, showFull, info_text, elapsed_seconds) {
+
+    var info = {};
+    if (info_text) {
+        info.text = info_text;
+    } else {
+        info.text = messages[''] || '';
+        // format numbers included in status nicely
+        /* @todo this pretty printing is hard to work out how to do in an Angularesque way:
+        info.text = info.text.replace(/\d{4,}/g,
+            function (match, position, string) {
+                return app.format_number(parseInt(match, 10));
+            }
+        );
+        */
+
+        var time_taken_text = messages['Time taken'];
+        info.timeTaken = parseSeconds(time_taken_text);
+    }
+    info.showDetails = false;
+
+    if (showFull) {
+        if (!elapsed_seconds) {
+            var time_taken_text = messages['Time taken'];
+            elapsed_seconds = parseSeconds(time_taken_text);
+        }
+
+        info.showDetails = true;
+
+        var document_config = {
+            'Requests': 'Total Requests made to DataSource',
+            'Fetched': 'Total Rows Fetched',
+            'Skipped': 'Total Documents Skipped',
+            'Processed': 'Total Documents Processed'
+        };
+
+        info.docs = [];
+        for (var key in document_config) {
+            var value = parseInt(messages[document_config[key]], 10);
+            var doc = {desc: document_config[key], name: key, value: value};
+            if (elapsed_seconds && key != 'Skipped') {
+                doc.speed = Math.round(value / elapsed_seconds);
+            }
+            info.docs.push(doc);
+        }
+
+        var dates_config = {
+            'Started': 'Full Dump Started',
+            'Aborted': 'Aborted',
+            'Rolledback': 'Rolledback'
+        };
+
+        info.dates = [];
+        for (var key in dates_config) {
+            var value = messages[dates_config[key]];
+            if (value) {
+                value = value.replace(" ", "T")+".000Z";
+                console.log(value);
+                var date = {desc: dates_config[key], name: key, value: value};
+                info.dates.push(date);
+            }
+        }
+    }
+    return info;
+}
+
+var parseSeconds = function(time) {
+    var seconds = 0;
+    var arr = new String(time || '').split('.');
+    var parts = arr[0].split(':').reverse();
+
+    for (var i = 0; i < parts.length; i++) {
+        seconds += ( parseInt(parts[i], 10) || 0 ) * Math.pow(60, i);
+    }
+
+    if (arr[1] && 5 <= parseInt(arr[1][0], 10)) {
+        seconds++; // treat more or equal than .5 as additional second
+    }
+    return seconds;
+}

Added: lucene/dev/trunk/solr/webapp/web/js/angular/controllers/replication.js
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/webapp/web/js/angular/controllers/replication.js?rev=1680118&view=auto
==============================================================================
--- lucene/dev/trunk/solr/webapp/web/js/angular/controllers/replication.js (added)
+++ lucene/dev/trunk/solr/webapp/web/js/angular/controllers/replication.js Mon May 18 22:35:59 2015
@@ -0,0 +1,227 @@
+/*
+ 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('ReplicationController',
+    function($scope, $rootScope, $routeParams, $interval, $timeout, Replication) {
+        $scope.resetMenu("replication");
+
+        $scope.iterationCount = 1;
+
+        $scope.refresh = function() {
+            Replication.details({core:$routeParams.core}, function(response) {
+                if ($scope.interval) $interval.cancel($scope.interval);
+                $scope.isSlave = (response.details.isSlave === 'true');
+                if ($scope.isSlave) {
+                    $scope.progress = getProgressDetails(response.details.slave);
+                    $scope.iterations = getIterations(response.details.slave);
+                    $scope.versions = getSlaveVersions(response.details);
+                    $scope.settings = getSlaveSettings(response.details);
+                    if ($scope.settings.isReplicating) {
+                        $timeout($scope.refresh, 1000);
+                    } else if(!$scope.settings.isPollingDisabled && $scope.settings.pollInterval) {
+                        $scope.interval = $interval(function() {
+                            $scope.settings.tick--;
+                        }, 1000, $scope.settings.tick);
+                        $timeout($scope.refresh, 1000*(1+$scope.settings.tick));
+                    }
+                } else {
+                    $scope.versions = getMasterVersions(response.details);
+                }
+                $scope.master = getMasterSettings(response.details, $scope.isSlave);
+            });
+
+        };
+
+        $scope.execute = function(command) {
+            Replication.command({core:$routeParams.core, command:command}, function(data){$scope.refresh()});
+        }
+
+        $scope.showIterations = function() { $scope.iterationCount = 100000}; // limitTo should accept undefined, but doesn't work.
+        $scope.hideIterations = function() { $scope.iterationCount = 1};
+
+        $scope.refresh();
+    });
+
+var getProgressDetails = function(progress) {
+
+    progress.timeRemaining = parseSeconds(progress.timeRemaining);
+    progress.totalPercent = parseInt(progress.totalPercent);
+    if (progress.totalPercent === 0) {
+        progress.totalPercentWidth = "1px";
+    } else {
+        progress.totalPercentWidth = progress.totalPercent + "%";
+    }
+    progress.currentFileSizePercent = parseInt(progress.currentFileSizePercent);
+
+    if (!progress.indexReplicatedAtList) {
+        progress.indexReplicatedAtList = [];
+    }
+
+    if (!progress.replicationFailedAtList) {
+        progress.replicationFailedAtList = [];
+    }
+    return progress;
+};
+
+var getIterations = function(slave) {
+
+    var iterations = [];
+
+    var find = function(list, date) {
+        return list.filter(function(e) {return e.date == date});
+    };
+
+    for (var i in slave.indexReplicatedAtList) {
+        var date = slave.indexReplicatedAtList[i];
+        var iteration = {date:date, status:"replicated", latest: false};
+        if (date == slave.indexReplicatedAt) {
+            iteration.latest = true;
+        }
+        iterations.push(iteration);
+    }
+
+    for (var i in slave.replicationFailedAtList) {
+        var failedDate = slave.replicationFailedAtList[i];
+        var matchingIterations = find(iterations, failedDate);
+        if (matchingIterations) {
+            iteration = matchingIterations[0];
+        } else {
+            iteration = {date: failedDate, latest:false};
+            iterations.push(iteration);
+        }
+        iteration.status = "failed";
+        if (failedDate == slave.replicationFailedAt) {
+            iteration.latest = true;
+        }
+    }
+    iterations.sort(function(a,b){ return a.date> b.date;}).reverse();
+    return iterations;
+};
+
+var getMasterVersions = function(data) {
+    versions = {masterSearch:{}, master:{}};
+
+    versions.masterSearch.version = data.indexVersion;
+    versions.masterSearch.generation = data.generation;
+    versions.masterSearch.size = data.indexSize;
+
+    versions.master.version = data.master.replicableVersion || '-';
+    versions.master.generation = data.master.replicableGeneration || '-';
+    versions.master.size = '-';
+
+    return versions;
+};
+
+var getSlaveVersions = function(data) {
+    versions = {masterSearch: {}, master: {}, slave: {}};
+
+    versions.slave.version = data.indexVersion;
+    versions.slave.generation = data.generation;
+    versions.slave.size = data.indexSize;
+
+    versions.master.version = data.slave.masterDetails.replicableVersion || '-';
+    versions.master.generation = data.slave.masterDetails.replicableGeneration || '-';
+    versions.master.size = '-';
+
+    versions.masterSearch.version = data.slave.masterDetails.indexVersion;
+    versions.masterSearch.generation = data.slave.masterDetails.generation;
+    versions.masterSearch.size = data.slave.masterDetails.indexSize;
+
+    versions.changedVersion = data.indexVersion !== data.slave.masterDetails.indexVersion;
+    versions.changedGeneration = data.generation !== data.slave.masterDetails.generation;
+
+    return versions;
+};
+
+var parseDateToEpoch = function(date) {
+    // ["Sat Mar 03 11:00:00 CET 2012", "Sat", "Mar", "03", "11:00:00", "CET", "2012"]
+    var parts = date.match( /^(\w+)\s+(\w+)\s+(\d+)\s+(\d+\:\d+\:\d+)\s+(\w+)\s+(\d+)$/ );
+
+    // "Sat Mar 03 2012 10:37:33"
+    var d = new Date( parts[1] + ' ' + parts[2] + ' ' + parts[3] + ' ' + parts[6] + ' ' + parts[4] );
+    return d.getTime();
+}
+
+var parseSeconds = function(time) {
+    var seconds = 0;
+    var arr = new String(time || '').split('.');
+    var parts = arr[0].split(':').reverse();
+
+    for (var i = 0; i < parts.length; i++) {
+        seconds += ( parseInt(parts[i], 10) || 0 ) * Math.pow(60, i);
+    }
+
+    if (arr[1] && 5 <= parseInt(arr[1][0], 10)) {
+        seconds++; // treat more or equal than .5 as additional second
+
+    }
+
+    return seconds;
+}
+
+var getSlaveSettings = function(data) {
+    var settings = {};
+    settings.masterUrl = data.slave.masterUrl;
+    settings.isPollingDisabled = data.slave.isPollingDisabled == 'true';
+    settings.pollInterval = data.slave.pollInterval;
+    settings.isReplicating = data.slave.isReplicating == 'true';
+    settings.nextExecutionAt = data.slave.nextExecutionAt;
+
+    if(settings.isReplicating) {
+        settings.isApprox = true;
+        settings.tick = parseSeconds(settings.pollInterval);
+    } else if (!settings.isPollingDisabled && settings.pollInterval) {
+        if( settings.nextExecutionAt ) {
+            settings.nextExecutionAtEpoch = parseDateToEpoch(settings.nextExecutionAt);
+            settings.currentTime = parseDateToEpoch(data.slave.currentDate);
+
+            if( settings.nextExecutionAtEpoch > settings.currentTime) {
+                settings.isApprox = false;
+                settings.tick = ( settings.nextExecutionAtEpoch - settings.currentTime) / 1000;
+            }
+        }
+    }
+    return settings;
+};
+
+var getMasterSettings = function(details, isSlave) {
+    var master = {};
+    var masterData = isSlave ? details.slave.masterDetails.master : details.master;
+    master.replicationEnabled = masterData.replicationEnabled == "true";
+    master.replicateAfter = masterData.replicateAfter.join(", ");
+
+    if (masterData.confFiles) {
+        master.files = [];
+        var confFiles = masterData.confFiles.split(',');
+        for (var i=0; i<confFiles.length; i++) {
+            var file = confFiles[i];
+            var short = file;
+            var title = file;
+            if (file.indexOf(":")>=0) {
+                title = file.replace(':', ' » ');
+                var parts = file.split(':');
+                if (isSlave) {
+                    short = parts[1];
+                } else {
+                    short = parts[0];
+                }
+            }
+            master.files.push({title:title, name:short});
+        }
+    }
+    return master;
+}