SOLR-7558: Uber-patch for Angular JS admin UI

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1680118 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Erick Erickson 2015-05-18 22:35:59 +00:00
parent 685a9f2643
commit a49a6b5dc4
26 changed files with 3881 additions and 229 deletions

View File

@ -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)

View File

@ -116,7 +116,7 @@ This file is generated by `grunt build`, do not edit it by hand.
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`, do not edit it by hand.
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`, do not edit it by hand.
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`, do not edit it by hand.
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`, do not edit it by hand.
}
.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`, do not edit it by hand.
.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;
}

View File

@ -180,6 +180,12 @@ ul
background-image: url( ../../img/loader-light.gif ) !important;
}
.universal-loader {
position: absolute;
left: 0px;
top: 0px;
}
#wrapper
{
position: relative;

View File

@ -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;
}

View File

@ -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

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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 );
}

View File

@ -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>

View File

@ -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,28 +360,94 @@ solrAdminApp.controller('MainController', function($scope, $routeParams, $rootSc
(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
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+)$/ );
// "Sat Mar 03 2012 10:37:33"
return new Date( parts[1] + ' ' + parts[2] + ' ' + parts[3] + ' ' + parts[6] + ' ' + parts[4] );
}
// @todo clear timeouts
this.bind
(
'error',
function( message, original_error )
{
alert( original_error.message );
}
);
// 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 );
*/

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,432 @@
/*
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 cookie_schema_browser_autoload = 'schema-browser_autoload';
solrAdminApp.controller('SchemaBrowserController',
function($scope, $routeParams, $location, $cookies, Luke) {
$scope.resetMenu("schema-browser");
$scope.refresh = function () {
Luke.schema({core: $routeParams.core}, function (schema) {
Luke.index({core: $routeParams.core}, function (index) {
var data = mergeIndexAndSchemaData(index, schema.schema);
$scope.fieldsAndTypes = getFieldsAndTypes(data);
$scope.is = {};
var search = $location.search();
leftbar = {};
$scope.isField = $scope.isDynamicField = $scope.isType = false;
if (search.field) {
$scope.selectedType = "Field";
$scope.is.field = true;
$scope.name = search.field;
leftbar.fields = [$scope.name];
var field = data.fields[$scope.name];
leftbar.types = [field.type];
if (field.dynamicBase) leftbar.dynamicFields = [field.dynamicBase];
if (field.copySources && field.copySources.length>0) leftbar.copyFieldSources = field.copySources.sort();
if (field.copyDests && field.copyDests.length>0) leftbar.copyFieldDests = field.copyDests.sort();
$scope.fieldOrType = "field=" + $scope.name;
} else if (search["dynamic-field"]) {
$scope.selectedType = "Dynamic Field";
$scope.is.dynamicField = true;
$scope.name = search["dynamic-field"];
leftbar.dynamicFields = [$scope.name];
leftbar.types = [data.dynamic_fields[$scope.name].type];
$scope.fieldOrType = "dynamic-field=" + $scope.name;
} else if (search.type) {
$scope.selectedType = "Type";
$scope.is.type = true;
$scope.name = search.type;
leftbar.types = [$scope.name];
leftbar.fields = filterFields("fields", data, $scope.name);
leftbar.dynamicFields = filterFields("dynamic_fields", data, $scope.name);
$scope.fieldOrType = "type=" + $scope.name;
}
$scope.leftbar = leftbar;
$scope.core = $routeParams.core;
$scope.defaultSearchField = data.default_search_field;
$scope.uniqueKeyField = data.unique_key_field;
$scope.isDefaultSearchField = ($scope.selectedType == "Field" && $scope.name == $scope.defaultSearchField);
$scope.isUniqueKeyField = ($scope.selectedType == "Field" && $scope.name == $scope.uniqueKeyField);
$scope.display = getFieldProperties(index, $routeParams.core, $scope.is, $scope.name);
$scope.analysis = getAnalysisInfo(data, $scope.is, $scope.name);
$scope.isAutoload = $cookies[cookie_schema_browser_autoload] == "true";
if ($scope.isAutoload) {
$scope.toggleTerms();
}
});
});
};
$scope.refresh();
$scope.selectFieldOrType = function() {
$location.search($scope.fieldOrType);
}
$scope.toggleAnalyzer = function(analyzer) {
analyzer.show = !analyzer.show;
}
$scope.loadTermInfo = function() {
var params = {fl: $scope.name, core: $routeParams.core};
if ($scope.topTermsCount) {
params.numTerms = $scope.topTermsCount;
}
$scope.isLoadingTerms = true;
Luke.field(params, function (data) {
$scope.isLoadingTerms = false;
$scope.termInfo = getTermInfo(data.fields[$scope.name]);
if (!$scope.topTermsCount) {
$scope.topTermsCount = $scope.termInfo.termCount;
}
});
}
$scope.toggleTerms = function() {
$scope.showTerms = !$scope.showTerms;
if ($scope.showTerms) {
$scope.loadTermInfo();
}
}
$scope.loadAllTerms = function() {
$scope.topTermsCount = $scope.termInfo.maxTerms;
$scope.loadTermInfo();
}
$scope.toggleAutoload = function() {
$scope.isAutoload = !$scope.isAutoload;
$cookies[cookie_schema_browser_autoload] = $scope.isAutoload;
console.log("cookie: " + $cookies[cookie_schema_browser_autoload]);
}
}
);
var getFieldsAndTypes = function(data) {
var fieldsAndTypes = [];
for (var field in data.fields) {
fieldsAndTypes.push({
group: "Fields",
value: "field=" + field,
label: field
});
}
for (var field in data.dynamic_fields) {
fieldsAndTypes.push({
group: "Dynamic Fields",
value: "dynamic-field=" + field,
label: field
});
}
for (var type in data.types) {
fieldsAndTypes.push({
group: "Types",
value: "type=" + type,
label: type
});
}
return fieldsAndTypes;
};
var filterFields = function(type, data, name) {
var fields = [];
for (var i in data.types[name].fields) {
var field = data.types[name].fields[i];
if (data[type][field]) {
fields.push(field)
}
}
return fields.sort();
}
var mergeIndexAndSchemaData = function(index, schema) {
var data = {
default_search_field: null,
unique_key_field: null,
key: {},
fields: {},
dynamic_fields: {},
types: {},
relations: {
f_df: {},
f_t: {},
df_f: {},
df_t: {},
t_f: {},
t_df: {}
}
};
data.fields = index.fields;
data.key = index.info.key;
data.default_search_field = schema.defaultSearchField;
data.unique_key_field = schema.uniqueKeyField;
data.dynamic_fields = schema.dynamicFields;
data.types = schema.types;
for (var field in schema.fields) {
data.fields[field] =
$.extend({}, data.fields[field], schema.fields[field]);
}
for (var field in data.fields) {
var copy_dests = data.fields[field].copyDests;
for (var i in copy_dests) {
var copy_dest = copy_dests[i];
if (!data.fields[copy_dest]) {
data.fields[copy_dest] = {
partial: true,
copySources: []
};
}
if (data.fields[copy_dest].partial) {
data.fields[copy_dest].copySources.push(field);
}
}
var copy_sources = data.fields[field].copySources;
for (var i in copy_sources) {
var copy_source = copy_sources[i];
if (!data.fields[copy_source]) {
data.fields[copy_source] = {
partial: true,
copyDests: []
};
}
if (data.fields[copy_source].partial) {
data.fields[copy_source].copyDests.push(field);
}
}
data.relations.f_t[field] = data.fields[field].type;
if (!data.relations.t_f[data.fields[field].type]) {
data.relations.t_f[data.fields[field].type] = [];
}
data.relations.t_f[data.fields[field].type].push(field);
if (data.fields[field].dynamicBase) {
data.relations.f_df[field] = data.fields[field].dynamicBase;
if (!data.relations.df_f[data.fields[field].dynamicBase]) {
data.relations.df_f[data.fields[field].dynamicBase] = [];
}
data.relations.df_f[data.fields[field].dynamicBase].push(field);
}
}
for (var dynamic_field in data.dynamic_fields) {
data.relations.df_t[dynamic_field] = data.dynamic_fields[dynamic_field].type;
if (!data.relations.t_df[data.dynamic_fields[dynamic_field].type]) {
data.relations.t_df[data.dynamic_fields[dynamic_field].type] = [];
}
data.relations.t_df[data.dynamic_fields[dynamic_field].type].push(dynamic_field);
}
return data;
};
var getFieldProperties = function(data, core, is, field) {
var display = {};
display.partialState = is.field && !!data.fields[field].partial;
display.columns = [];
display.rows = [];
var allFlags = "";
var addRow = function(name, flags) {
if (flags[0]!='(') {
display.rows.push({name:name, flags:flags});
for (var i in flags) {
if (flags[i]!="-" && allFlags.indexOf(flags[i])<0) {
allFlags+=flags[i];
}
}
} else {
display.rows.push({name:name, comment:flags});
}
}
// Identify the rows for our field property table
if (is.field && data.fields[field]) {
if (data.fields[field].flags) {
addRow('Properties', data.fields[field].flags);
}
if (data.fields[field].schema) {
addRow('Schema', data.fields[field].schema);
}
if (data.fields[field].index) {
addRow('Index', data.fields[field].index);
}
display.docs = data.fields[field].docs;
display.docsUrl = "#/" + core + "/query?q=" + field + ":[* TO *]";
display.distinct = data.fields[field].distinct;
display.positionIncrementGap = data.fields[field].positionIncrementGap;
display.similarity = data.fields[field].similarity;
} else if (is.dynamicField && data.dynamic_fields[field] && data.dynamic_fields[field].flags) {
addRow('Properties', data.dynamic_fields[field].flags);
}
// identify columns in field property table:
for (var key in data.info.key) {
if (allFlags.indexOf(key)>=0) {
display.columns.push({key: key, name: data.info.key[key]});
}
}
// identify rows and cell values in field property table:
for (var i in display.rows) {
var row = display.rows[i];
row.cells = [];
for (var j in display.columns) {
var flag = display.columns[j].key;
row.cells.push({key: flag, value: row.flags.indexOf(flag)>=0});
}
}
return display;
};
var getAnalysisInfo = function(data, is, name) {
var analysis = {};
if (is.field) {
var type = data.relations.f_t[name];
analysis.query = "analysis.fieldname=" + name;
}
else if (is.dynamicField) {
var type = data.relations.df_t[name];
analysis.query = "analysis.fieldtype=" + type;
}
else if (is.type) {
var type = name;
analysis.query = "analysis.fieldtype=" + name;
}
var processComponentType = function (label, key, componentTypeData) {
if (componentTypeData) {
var components = [];
console.dir(componentTypeData);
for (var componentName in componentTypeData) {
console.log(componentName);
var componentData = componentTypeData[componentName];
var component = {className: componentData.className, args:[]};
if (componentData.args) {
for (var argName in componentData.args) {
var argValue = componentData.args[argName];
if (argValue == "1" || argValue == "true") {
component.args.push({name: argName, booleanValue:true});
} else if (argValue == "0" || argValue == "false") {
component.args.push({name: argName, booleanValue:false});
} else {
component.args.push({name: argName, value:argValue});
}
}
}
components.push(component);
}
return {label: label, key: key, components: components};
} else {
return {label: label, key: key};
}
}
var buildAnalyzer = function (analyzerData) {
var analyzer = {};
analyzer.className = analyzerData.className;
analyzer.componentTypes = [];
if (analyzerData.tokenizer) {
analyzer.componentTypes.push(processComponentType("Char Filters", "charFilters", analyzerData.charFilters));
analyzer.componentTypes.push(processComponentType("Tokenizer", "tokenizer", {tokenizer: analyzerData.tokenizer}));
analyzer.componentTypes.push(processComponentType("Token Filters", "tokenFilters", analyzerData.filters));
}
return analyzer;
}
analysis.data = data.types[type];
if (analysis.data) {
analysis.analyzers = [
{key: "index", name: "Index", detail: buildAnalyzer(analysis.data.indexAnalyzer)},
{key: "query", name: "Query", detail: buildAnalyzer(analysis.data.queryAnalyzer)}
];
}
return analysis;
}
var getTermInfo = function(data) {
var termInfo = {};
if (data && data.topTerms) {
termInfo.topTerms = [];
var currentGroup = {count: 0}
for (var i = 0; i < data.topTerms.length; i += 2) {
var count = data.topTerms[i + 1];
if (currentGroup.count != count) {
currentGroup = {count: count, terms: []};
termInfo.topTerms.push(currentGroup);
}
currentGroup.terms.push(data.topTerms[i]);
}
termInfo.termCount = data.topTerms.length / 2;
termInfo.maxTerms = data.distinct;
}
if(data && data.histogram) {
termInfo.histogram = [];
termInfo.histogramMax = 0;
for (var i = 0; i < data.histogram.length; i += 2) {
termInfo.histogram.push({key: data.histogram[i], value: data.histogram[i + 1]});
termInfo.histogramMax = Math.max(termInfo.histogramMax, data.histogram[i + 1]);
}
}
return termInfo;
};
/*
var get_width = function get_width()
{
return $( this ).width();
}
var max_width = 10 + Math.max.apply( Math, $( 'p', topterms_table_element ).map( get_width ).get() );
topterms:
p { width: {{maxWidth}}px !important; }
ul { margin-left: {{max_width + 5 }}px !important; }
var max_width = 10 + Math.max.apply( Math, $( 'dt', histogram_holder_element ).map( get_width ).get() );
histogram_holder:
ul { margin-left: {{maxWidth}}px !important; }
li dt { left: {{-maxWidth}}px !important; width: {{maxWidth}}px !important; }
*/

View File

@ -0,0 +1,94 @@
/*
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 MB_FACTOR = 1024*1024;
solrAdminApp.controller('SegmentsController', function($scope, $routeParams, $interval, Segments) {
$scope.resetMenu("segments");
$scope.refresh = function() {
Segments.get({core: $routeParams.core}, function(data) {
var segments = data.segments;
var segmentSizeInBytesMax = getLargestSegmentSize(segments);
$scope.segmentMB = Math.floor(segmentSizeInBytesMax / MB_FACTOR);
$scope.xaxis = calculateXAxis(segmentSizeInBytesMax);
$scope.documentCount = 0;
$scope.deletionCount = 0;
$scope.segments = [];
for (var name in segments) {
var segment = segments[name];
var segmentSizeInBytesLog = Math.log(segment.sizeInBytes);
var segmentSizeInBytesMaxLog = Math.log(segmentSizeInBytesMax);
segment.totalSize = Math.floor((segmentSizeInBytesLog / segmentSizeInBytesMaxLog ) * 100);
segment.deletedDocSize = Math.floor((segment.delCount / (segment.delCount + segment.totalSize)) * segment.totalSize);
if (segment.delDocSize <= 0.001) delete segment.deletedDocSize;
segment.aliveDocSize = segment.totalSize - segment.deletedDocSize;
$scope.segments.push(segment);
$scope.documentCount += segment.size;
$scope.deletionCount += segment.delCount;
}
$scope.deletionsPercentage = calculateDeletionsPercentage($scope.documentCount, $scope.deletionCount);
});
};
$scope.toggleAutoRefresh = function() {
$scope.autorefresh = !$scope.autorefresh;
if ($scope.autorefresh) {
$scope.interval = $interval($scope.refresh, 1000);
} else if ($scope.interval) {
$interval.cancel($scope.interval);
}
};
$scope.refresh();
});
var calculateXAxis = function(segmentInBytesMax) {
var steps = [];
var log = Math.log(segmentInBytesMax);
for (var j=0, step=log/4; j<3; j++, step+=log/4) {
steps.push({pos:j, value:Math.floor((Math.pow(Math.E, step))/MB_FACTOR)})
}
return steps;
};
var getLargestSegmentSize = function(segments) {
var max = 0;
for (var name in segments) {
max = Math.max(max, segments[name].sizeInBytes);
}
return max;
};
var calculateDeletionsPercentage = function(docCount, delCount) {
if (docCount == 0) {
return 0;
} else {
var percent = delCount / docCount * 100;
return Math.round(percent * 100) / 100;
}
};

View File

@ -67,8 +67,9 @@ solrAdminServices.factory('System',
}])
.factory('Replication',
['$resource', function($resource) {
return $resource('/solr/:core/replication', {'wt':'json', core: "@core", 'command': 'details', '_':Date.now()}, {
"details": {params: {command: "details"}}
return $resource('/solr/:core/replication', {'wt':'json', core: "@core", '_':Date.now()}, {
"details": {params: {command: "details"}},
"command": {params: {}}
});
}])
.factory('CoreSystem',
@ -106,8 +107,21 @@ solrAdminServices.factory('System',
.factory('Luke',
['$resource', function($resource) {
return $resource('/solr/:core/admin/luke', {core: '@core', wt:'json', _:Date.now()}, {
"index": {params: {numTerms: 0}},
"schema": {params: {show:'schema'}},
"index": {params: {show:'index', numTerms: 0}}
"field": {},
"fields": {params: {show:'schema'}, interceptor: {
response: function(response) {
var fieldsAndTypes = [];
for (var field in response.data.schema.fields) {
fieldsAndTypes.push({group: "Fields", label: field, value: "fieldname=" + field});
}
for (var type in response.data.schema.types) {
fieldsAndTypes.push({group: "Types", label: type, value: "fieldtype=" + type});
}
return fieldsAndTypes;
}
}}
});
}])
.factory('Analysis',
@ -116,6 +130,19 @@ solrAdminServices.factory('System',
"field": {params: {"analysis.showmatch": true}}
});
}])
.factory('DataImport',
['$resource', function($resource) {
return $resource('/solr/:core/dataimport', {core: '@core', indent:'on', wt:'json', _:Date.now()}, {
"config": {params: {command: "show-config"}, transformResponse: function(data) {
return {config: data};
}},
"status": {params: {command: "status"}},
"reload": {params: {command: "reload-config"}},
"post": {method: "POST",
headers: {'Content-type': 'application/x-www-form-urlencoded'},
transformRequest: function(data) { return $.param(data) }}
});
}])
.factory('Ping',
['$resource', function($resource) {
return $resource('/solr/:core/admin/ping', {wt:'json', core: '@core', ts:Date.now(), _:Date.now()}, {
@ -127,6 +154,7 @@ solrAdminServices.factory('System',
['$resource', function($resource) {
return $resource('/solr/:core/admin/mbeans', {'wt':'json', core: '@core', '_':Date.now()}, {
stats: {params: {stats: true}},
info: {},
reference: {
params: {wt: "xml", stats: true}, transformResponse: function (data) {
return {reference: data}
@ -161,11 +189,11 @@ solrAdminServices.factory('System',
}).success(callback);
}
}}
])
.factory('Segments',
['$resource', function($resource) {
return $resource('/solr/:core/admin/segments', {'wt':'json', core: '@core', _:Date.now()}, {
get: {}
});
}
]);
/*
http://localhost:8983/solr/techproducts/admin/mbeans?cat=QUERYHANDLER&wt=json&_=1419614354276
PING:
http://localhost:8983/solr/techproducts/admin/ping?wt=json&ts=1419614393324&_=1419614393325
*/

View File

@ -41,7 +41,7 @@ limitations under the License.
<li class="settings-holder clearfix">
<div class="settings clearfix">
<label for="type_or_name">Analyse Fieldname / FieldType:</label>
<select id="type_or_name" ng-model="fieldOrType" ng-options="f.value as f.label group by f.group for f in fieldsAndTypes"></select>
<select chosen id="type_or_name" ng-model="fieldOrType" ng-options="f.value as f.label group by f.group for f in fieldsAndTypes"></select>
<a id="tor_schema" href="#"><span>Schema Browser</span>&nbsp;</a>

View File

@ -17,15 +17,15 @@ limitations under the License.
<div id="cloud" class="clearfix">
<div id="frame">
{{here}}
<div id="tree-content" class="content clearfix" ng-show="showTree">
<jstree class="tree" on-select="showTreeLink(url)" config="jstree" data="tree" id="tree"></jstree>
<jstree class="tree" on-select="showTreeLink(url)" id="tree"></jstree>
<div id="file-content" class="clearfix">
<div id="prop" ng-show="znode.prop && showData">
<ul>
<li ng-class:"odd:$odd" ng-repeat="(key, prop) in znode.prop">
<li ng-class="{odd:$odd}" ng-repeat="(key, prop) in znode.prop">
<dl class="clearfix">
<dt>{{ key }}</dt>
<dd>{{ prop }}</dd>

View File

@ -33,7 +33,7 @@ limitations under the License.
<dt>Last Modified:</dt>
<dd class="value">{{index.lastModified | timeago}}</dd>
<dt>Num Docs:</dt>
<dt class="index_num-docs">Num Docs:</dt>
<dd class="value">{{index.numDocs}}</dd>
<dt class="index_max-doc">Max Doc:</dt>

View File

@ -0,0 +1,209 @@
<!--
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.
-->
<div id="dataimport" class="clearfix">
<div ng-show="!hasHandlers">Sorry, no dataimport-handler defined!</div>
<div id="frame" ng-show="hasHandlers">
<div id="error" ng-show="error"></div>
<div id="current_state" class="{{status}}">
<p class="last_update">Last Update: <abbr title="{{lastUpdateUTC}}">{{lastUpdate}}</abbr></p>
<div class="info">
<strong>{{info.text}}<span ng-show="info.timeTaken"> (Duration: {{info.timeTaken | readableSeconds }})</span>
</strong>
<div class="details" ng-show="info.showDetails">
<div class="docs">
<span ng-repeat="doc in info.docs">
<abbr style="display:inline" title="{{ doc.desc }}">{{ doc.name }}</abbr>: {{doc.value | number}}<!-- remove whitespace!
--><span style="display:inline" ng-show="doc.speed">{{ doc.speed | number}}/s</span><!-- remove whitespace!
--><span style="display:inline" ng-show="!$last">, </span>
</span>
</div>
<div class="dates">
<span ng-repeat="date in info.dates">
<abbr title="{{ date.desc }}">{{ date.name }}</abbr>:
<abbr class="time">{{ date.value | timeago }}</abbr>
</span>
</div>
</div>
<button class="abort-import" ng-class="{warn:!isAborting, success: isAborting}" ng-click="abort()" ng-show="isRunning">
<span ng-show="isAborting">Aborting Import</span>
<span ng-show="!isAborting">Abort Import</span>
</button>
</div>
</div>
<div class="block" id="raw_output" >
<h2>
<a class="toggle" ng-click="toggleRawStatus()"><span>Raw Status-Output</span></a>
</h2>
<div class="message-container" ng-show="showRawStatus">
<div class="message"></div>
</div>
<div class="content" ng-show="showRawStatus">
<div id="raw_output_container"><pre class="syntax language-json"><code ng-bind-html="rawStatus | highlight:'json' | unsafe"></code></pre></div>
</div>
</div>
<div class="block" id="config" ng-class="{debug_mode:isDebugMode}">
<h2 class="clearfix">
<a class="toggle" ng-click="toggleConfiguration()"><span>Configuration</span></a>
<a class="r reload_config" ng-class="{success:reloaded}" ng-click="reload()" title="Reload Configuration">Reload</a>
<a class="r debug_mode" ng-click="toggleDebug()">Debug-Mode</a>
</h2>
<div class="message-container" ng-show="showConfiguration">
<div class="message"></div>
</div>
<div class="content" ng-show="showConfiguration">
<div id="dataimport_config">
<div class="formatted" ng-show="!isDebugMode">
<pre class="syntax language-xml"><code ng-bind-html="config | highlight:'xml'| unsafe"></code></pre>
</div>
<div class="editable" ng-show="isDebugMode">
<textarea>{{config}}</textarea>
</div>
</div>
</div>
</div>
<div class="block" id="debug_response" ng-show="form.showDebug">
<h2>
<a class="toggle" ng-click="toggleRawDebug()"><span>Raw Debug-Response</span></a>
</h2>
<div class="message-container" ng-show="showRawDebug">
<div class="message"></div>
</div>
<div class="content" ng-show="showRawDebug">
<span ng-show="true">
<em>No Request executed</em>
</span>
<span ng-show="false">
<pre class="syntax language-json"><code ng-bind-html="rawResponse | highlight:'xml' | unsafe"></code></pre>
</span>
</div>
</div>
</div>
<div id="form" ng-show="hasHandlers">
<div id="navigation">
<ul>
<li ng-class="{current: currentHandler == handler}" ng-repeat="handler in handlers">
<a href="#/{{form.core}}/dataimport/{{handler}}">{{handler}}</a>
</li>
</ul>
</div>
<form action="#" method="get">
<label for="command">
<a rel="help">Command</a>
</label>
<select name="command" id="command" ng-model="form.command">
<option>full-import</option>
<option>delta-import</option>
</select>
<label for="verbose" class="checkbox">
<input type="checkbox" name="verbose" id="verbose" ng-model="form.verbose">
Verbose
</label>
<label for="clean" class="checkbox">
<input type="checkbox" name="clean" id="clean" ng-model="form.clean">
Clean
</label>
<label for="commit" class="checkbox">
<input type="checkbox" name="commit" id="commit" ng-model="form.commit">
Commit
</label>
<label for="optimize" class="checkbox">
<input type="checkbox" name="optimize" id="optimize" ng-model="form.optimize">
Optimize
</label>
<label for="debug" class="checkbox">
<input type="checkbox" name="debug" id="debug" ng-model="form.showDebug">
Debug
</label>
<label for="entity">
<a rel="help">Entity</a>
</label>
<select ng-model="form.entity" id="entity">
<option value=""></option>
<option ng-repeat="entity in entities">{{entity}}</option>
</select>
<label for="start">
<a rel="help">Start</a>,
<a rel="help">Rows</a>
</label>
<div class="clearfix">
<input type="text" id="start" placeholder="0" ng-model="form.start">
<input type="text" id="rows" placeholder="10" ng-model="form.rows">
</div>
<label for="custom_parameters">
<a rel="help">Custom Parameters</a>
</label>
<input type="text" id="custom_parameters" ng-model="form.custom" placeholder="key1=val1&amp;key2=val2">
</form>
<button class="execute" type="submit" ng-click="submit()">
<span ng-show="isDebugMode">Execute with this Configuration →</span>
<span ng-show="!isDebugMode">Execute</span>
</button>
<button class="refresh-status" ng-click="refreshStatus()" ng-class="{loader: isStatusLoading, success: statusUpdated}"><span>Refresh Status</span></button>
<p id="auto-refresh-status"><a ng-click="updateAutoRefresh()" ng-class="{on:autorefresh}">Auto-Refresh Status</a></p>
</div>
</div>

View File

@ -0,0 +1,118 @@
<!--
/*
* 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.
*/
-->
<div id="documents" class="clearfix">
<div id="form">
<form>
<label for="qt">
<a rel="help">Request-Handler (qt)</a>
</label>
<input ng-model="handler" type="text" id="qt" value="/update" title="Request handler in solrconfig.xml.">
<label for="document-type">
<a rel="help">Document Type</a>
</label>
<div><select ng-model="type" id="document-type" ng-change="changeDocumentType()" placeholder="The type of the document field">
<!-- TODO: support the Builder -->
<option value="csv">CSV</option>
<option value="wizard">Document Builder</option>
<option value="upload">File Upload</option>
<option value="json">JSON</option>
<option value="solr">Solr Command (raw XML or JSON)</option>
<option value="xml">XML</option>
</select>
</div>
<div id="document-container">
<div id="wizard" ng-show="type=='wizard'">
<div id="wizard-fields">
<div><span class="description">Field</span>: <select ng-model="fieldName" id="wiz-field-select" name="wiz-field-select"
ng-options="field for field in fields"></select>
</div>
<div><span id="wiz-field-data"><span class="description">Field Data</span>:</span>
<textarea ng-model="fieldData"
id="wizard-doc"
name="wizard-doc"
rows="10"
cols="40"
placeholder="Enter your field text here and then click 'Add Field' to add the field to the document.">
</textarea>
</div>
</div>
<div id="wizard-add"><a ng-click="addWizardField()" id="add-field-href"><img border="0" src="./img/ico/plus-button.png"/>Add
Field</a></div>
</div>
<label for="document">
<a rel="help">Document(s)</a>
</label>
<textarea ng-show="type!='upload'" ng-model="document" name="document" id="document" title="The Document" rows="10"
cols="70" placeholder="{{placeholder}}"></textarea>
<div id="file-upload" ng-show="type=='upload'">
<input type="file" id="the-file" name="the-file" file-model="fileUpload"/>
</div>
</div>
<div id="advanced">
<!-- TODO: only show for JSON/XML-->
<div id="attribs">
<div id="upload-only" ng-show="type=='upload'">
<label for="erh-params"><!-- TODO: cleaner way to do this? -->
<a rel="help">Extracting Req. Handler Params</a>
</label>
<input ng-model="literalParams" type="text" id="erh-params" value="&literal.id=change.me"
title="Extracting Request Handler Parameters" size="50">
</div>
<div id="general-attribs">
<label for="commitWithin">
<a rel="help">Commit Within</a>
</label>
<input type="text" ng-model="commitWithin" id="commitWithin" value="1000" title="Commit Within (ms)">
<label for="overwrite">
<a rel="help">Overwrite</a>
</label>
<input ng-model="overwrite" type="text" id="overwrite" value="true" title="Overwrite">
</div>
<!-- Boost is json only, since the XML has it embedded -->
<div id="json-only" ng-show="type=='json'">
<label for="boost">
<a rel="help">Boost</a>
</label>
<input ng-model="boost" type="text" id="boost" value="1.0" title="Document Boost">
</div>
</div>
</div>
<button type="submit" ng-click="submit()" id="submit">Submit Document</button>
</form>
</div>
<div id="result">
<div id="response" ng-show="response">
<div>
<span class="description">Status: </span>{{ responseStatus }}
</div>
<div>
<span class="description">Response:</span>
<pre class="syntax language-json"><code ng-bind-html="response | highlight:'json' | unsafe"></code></pre>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,47 @@
<!--
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.
-->
<div id="files" class="clearfix">
<div id="frame">
<div id="tree-holder">
<jstree class="tree" on-select="showTreeLink(data)" data="tree" id="tree"></jstree>
</div>
<div id="file-content" class="clearfix">
<div class="top clearfix">
<a id="url" class="address-bar" href="{{url}}" ng-show="url">{{url}}</a>
</div>
<div class="view-file">
<div class="response" ng-show="content">
<pre class="syntax language-{{lang}}"><code ng-bind-html="content | highlight:lang | unsafe"></code></pre>
</div>
</div>
</div>
</div>
</div>

View File

@ -25,6 +25,7 @@ limitations under the License.
<tr>
<th class="time">Time (<span>{{timezone}}</span>)</th>
<th class="level">Level</th>
<th class="core">Core</th>
<th class="logger">Logger</th>
<th class="message">Message</th>
</tr>
@ -33,6 +34,7 @@ limitations under the License.
<tr ng-click="toggleRow(event)" class="{{event.trace ? 'has-trace': ''}} {{'level-'+event.level.toLowerCase()}}">
<td class="span"><a><span>{{ timezone == "UTC" ? event.utc_time : event.local_time }}</span></a></td>
<td class="level span"><a><span>{{ event.level }} {{event.showTrace}}</span></span></a></td>
<td class="span"><a><span>{{ event.core }}</span></a></td>
<td class="span"><a><span><abbr title="{{event.logger}}">{{event.loggerBase}}</abbr></span></a></td>
<td class="message span"><a><span>{{ event.message }}</span></a></td>
</tr>

View File

@ -0,0 +1,72 @@
<!--
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.
-->
<div id="plugins" class="clearfix">
<div id="frame">
<ul>
<li class="entry" ng-class="{changed: plugin.changed}" ng-repeat="plugin in type.plugins">
<a ng-click="selectPlugin(plugin)">
<span>{{ plugin.name }}</span>
</a>
<ul class="detail" ng-show="plugin.open">
<li ng-repeat="(key, value) in plugin.properties" ng-class="{odd: $odd}">
<dl class="clearfix">
<dt>{{ key }}:</dt>
<!--<dd ng-repeat="v in value">{{v}}</dd><!-- is AN ARRAY!!-->
<dd>{{value}}</dd>
</dl>
</li>
<li class="stats clearfix" ng-show="plugin.stats">
<span>stats:</span>
<ul>
<li ng-repeat="(key, value) in plugin.stats" ng-class="{odd: $odd}">
<dl class="clearfix">
<dt>{{key}}:</dt>
<dd>{{value}}</dd>
</dl>
</li>
</ul>
</li>
</ul>
</ul>
</div>
<div id="navigation" class="clearfix">
<ul>
<li ng-repeat="type in types" class="{{type.lower}}">
<a ng-click="selectPluginType(type)" rel="{{type.name}}">{{type.name}}
<span ng-show="type.changes">{{type.changes}}</span>
</a>
</li>
<li class="PLUGINCHANGES"><a ng-click="startRecording()">Watch Changes</a></li>
<li class="RELOAD"><a ng-click="refresh()">Refresh Values</a></li>
</ul>
</div>
<div id="recording" ng-show="isRecording">
<div class="wrapper clearfix">
<p class="loader">Watching for Changes</p>
<button class="primary" ng-click="stopRecording()">Stop &amp; Show Changes</button>
</div>
<div id="blockUI"></div>
</div>
</div>

View File

@ -0,0 +1,239 @@
<!--
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.
-->
<div id="replication" class="clearfix" ng-class="{replicating:settings.isReplicating}">
<div id="frame">
<div id="error" ng-show="progress.ERROR">{{ progress.ERROR }}</div>
<div class="replicating block" ng-show="settings.isReplicating">
<div id="progress">
<div id="start"><div class="info">
<span>{{progress.replicationStartTime}}</span>
</div></div>
<div id="speed"><div class="info">
<span>5.1 MB</span>/s
</div></div>
<div id="bar">
<div id="bar-info"><div class="info">
<div class="files"><span>{{progress.numFilesToDownload}}</span> File<span ng-show="progress.numFilesToDownload&gt;1">s</span></div>
<div class="size"><span>{{progress.bytesToDownload}}</span></div>
</div></div>
<div id="eta"><div class="info">
ETA: <span>{{progress.timeRemaining | readableSeconds }}</span>
</div></div>
<div id="done" style="width: {{progress.totalPercentWidth}}">
<div class="percent">
<span>{{progress.totalPercent}}</span>%
</div>
<div id="done-info"><div class="info">
<div class="files"><span>{{progress.numFilesDownloaded}}</span> File<span ng-show="progress.numFilesDownloaded&gt;1">s</span></div>
<div class="size"><span>{{progress.bytesDownloaded}}</span></div>
</div></div>
</div>
</div>
</div>
<div id="current-file" class="clearfix">
<div class="label"><span class="loader">Current File:</span></div>
<div class="file">{{progress.currentFile}}</div>
<div class="progress">
<span class="done">{{progress.currentFileSizeDownloaded}}</span> / <span class="total">{{progress.currentFileSize}}</span> [<span class="percent">{{progress.currentFileSizePercent}}</span>%]
</div>
</div>
</div>
<div id="iterations" class="slaveOnly block clearfix" ng-show="isSlave">
<div class="label"><span class="">Iterations:</span></div>
<div class="iterations" ng-show="iterations && showIterations">
<ul>
<li class="{{iteration.status}}" ng-class="{latest:iteration.latest}" ng-repeat="iteration in iterations |limitTo:iterationCount">{{iteration.date}}</li>
</ul>
<span ng-show="iterations.length&gt;1">
<a ng-show="iterationCount==1" ng-click="showIterations()"><span class="expand">Show all Iterations</span></a>
<a ng-show="iterationCount&gt;1" ng-click="hideIterations()"><span class="collapse">Hide past Iterations</span></a>
</span>
</div>
</div>
<div id="details" class="block clearfix">
<table border="0" cellspacing="0" cellpadding="0">
<thead>
<tr>
<td><span>Index</span></td>
<th>Version</th>
<th><abbr title="Generation">Gen</abbr></th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr class="masterSearch">
<th>Master (Searching)</th>
<td class="version" ng-class="{diff:versions.changedVersion}">
<div>{{versions.masterSearch.version}}</div>
</td>
<td class="generation" ng-class="{diff:versions.changedGeneration}">
<div>{{versions.masterSearch.generation}}</div>
</td>
<td class="size">
<div>{{versions.masterSearch.size}}</div>
</td>
</tr>
<tr class="master">
<th>Master (Replicable)</th>
<td class="version" ng-class="{diff:versions.changedVersion}">
<div>{{versions.master.version}}</div>
</td>
<td class="generation" ng-class="{diff:versions.changedGeneration}">
<div>{{versions.master.generation}}</div>
</td>
<td class="size">
<div>{{versions.master.size}}</div>
</td>
</tr>
<tr class="slave slaveOnly" ng-show="isSlave">
<th>Slave (Searching)</th>
<td class="version" ng-class="{diff:versions.changedVersion}">
<div>{{versions.slave.version}}</div>
</td>
<td class="generation" ng-class="{diff:versions.changedGeneration}">
<div>{{versions.slave.generation}}</div>
</td>
<td class="size">
<div>{{versions.slave.size}}</div>
</td>
</tr>
</tbody>
</table>
</div>
<div id="settings" class="settings block clearfix slaveOnly" ng-show="isSlave">
<div class="label"><span>Settings:</span></div>
<ul>
<li class="masterUrl" ng-show="settings.masterUrl">
<dl class="clearfix">
<dt>master url:</dt>
<dd>{{settings.masterUrl}}</dd>
</dl>
</li>
<li class="isPollingDisabled"><dl class="clearfix">
<dt>polling enable:</dt>
<dd class="ico" ng-class="{'ico-0':settings.isPollingDisabled, 'ico-1':!settings.isPollingDisabled}">
<span ng-show="settings.pollInterval">(interval: {{settings.pollInterval}})</span>&nbsp;
</dd>
</dl></li>
</ul>
</div>
<div id="master-settings" class="settings block clearfix">
<div class="label"><span>Settings (Master):</span></div>
<ul>
<li class="replicationEnabled"><dl class="clearfix">
<dt>replication enable:</dt>
<dd class="ico" ng-class="{'ico-0':!master.replicationEnabled, 'ico-1':master.replicationEnabled}">&nbsp;</dd>
</dl></li>
<li class="replicateAfter"><dl class="clearfix">
<dt>replicateAfter:</dt>
<dd>{{master.replicateAfter}}</dd>
</dl></li>
<li class="confFiles" ng-show="master.files"><dl class="clearfix">
<dt>confFiles:</dt>
<dd><span ng-repeat="file in master.files"><attr title="{{file.title}}">{{file.name}}</attr>{{ $last ? '' :', '}}</span></dd>
</dl></li>
</ul>
</div>
</div>
<div id="navigation">
<div class="timer" ng-show="isSlave && !settings.isPollingDisabled &&!settings.isReplicating">
<p>Next Run: <span class="approx" ng-show="settings.isApprox">~</span><span class="tick">{{settings.tick | readableSeconds}}</span></p>
<small ng-show="settings.nextExecutionAt">{{settings.nextExecutionAt}}</small>
</div>
<button class="refresh-status" ng-click="refresh()"><span>Refresh Status</span></button>
<div class="slaveOnly" ng-show="isSlave">
<button class="optional replicate-now primary" ng-click="execute('fetchindex')" ng-show="!settings.isReplicating"><span>Replicate now</span></button>
<button class="optional abort-replication warn" ng-click="execute('abortfetch')" ng-show="settings.isReplicating"><span>Abort Replication</span></button>
<button class="optional disable-polling" ng-click="execute('disablepoll')" ng-show="!settings.isPollingDisabled"><span>Disable Polling</span></button>
<button class="optional enable-polling" ng-click="execute('enablepoll')" ng-show="settings.isPollingDisabled"><span>Enable Polling</span></button>
</div>
<div class="masterOnly" ng-show="!isSlave">
<button class="optional disable-replication warn" ng-click="execute('disablereplication')" ng-show="master.replicationEnabled"><span>Disable Replication</span></button>
<button class="optional enable-replication warn" ng-click="execute('enablereplication')" ng-show="!master.replicationEnabled"><span>Enable Replication</span></button>
</div>
</div>
</div>

View File

@ -0,0 +1,206 @@
<!--
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.
-->
<div id="schema-browser" class="loaded">
<div class="clearfix">
<div id="data">
<div id="field">
<div class="field-options">
<div class="block head">
<h2>
<span class="type">{{selectedType}}</span>:
<span class="name">{{name}}</span>
</h2>
</div>
<div class="partial" ng-show="partialState">
<p>Because your Index is empty, we do not have enough Information about this Field</p>
</div>
<dl class="options clearfix">
<dt class="field-type">Field-Type:</dt>
<dd class="field-type">{{analysis.data.className}}</dd>
<dt class="similarity" ng-show="display.similarity">Similarity:</dt>
<dd class="similarity" ng-show="display.similarity">{{ display.similarity.details }} ({{ similarity.className }}) </dd>
<dt class="position-increment-gap" ng-show="display.positionIncrementGap"><abbr title="Position Increment Gap">PI Gap</abbr>:</dt>
<dd class="position-increment-gap" ng-show="display.positionIncrementGap">{{ display.positionIncrementGap }}</dd>
<dt class="docs" ng-show="display.docs">Docs:</dt>
<dd class="docs" ng-show="display.docs"><a href="{{display.docsUrl}}">{{display.docs | number}}</a></dd>
<dt class="distinct" ng-show="display.distinct">Distinct:</dt>
<dd class="distinct" ng-show="display.distinct">{{display.distinct}}</dd>
</dl>
<table class="flags" cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<td>Flags:</td>
<th ng-repeat="key in display.columns">{{key.name}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in display.rows track by row.name">
<th>{{row.name}}</th>
<td colspan="2" class="text" ng-show="row.comment">{{row.comment}}</td>
<td ng-repeat="cell in row.cells"
ng-class="{'check':cell.value}">
<span ng-show="cell.value"></span>
<span ng-show="!cell.value">&nbsp;</span>
</td>
</tr>
</tbody>
</table>
<ul class="analyzer">
<li class="clearfix {{analyzer.key}}" ng-class="{open: analyzer.show}" ng-repeat="analyzer in analysis.analyzers">
<p><a class="analysis" ng-href="#/{{core}}/analysis?{{analysis.query}}"><span>{{analyzer.name}}&nbsp;Analyzer:</span></a></p>
<dl>
<dt><a ng-click="toggleAnalyzer(analyzer)" class="toggle">{{analyzer.detail.className}}</a></dt>
</dl>
<ul ng-show="analyzer.show">
<li class="clearfix {{componentType.key}} data" ng-repeat="componentType in analyzer.detail.componentTypes" ng-show="componentType.components">
<p>{{componentType.label}}:</p>
<dl>
<dt ng-repeat-start="component in componentType.components">{{component.className}}</dt>
<dd ng-repeat-end ng-repeat="arg in component.args"
ng-class="{'ico-1': arg.booleanValue, 'ico-0': arg.booleanValue==false}">
{{arg.name}}<span ng-show="arg.value">: {{arg.value}}</span>
</dd>
</dl>
</li>
</ul>
</li>
</ul>
</div>
<div class="terminfo-holder loaded clearfix" ng-class="{disabled: noTermData}" ng-show="is.field">
<div class="trigger">
<button class="submit" ng-click="toggleTerms()"><span ng-class="{loader:isLoadingTerms}">Load Term Info</span></button>
<a ng-show="showTerms" ng-click="toggleAutoload()" ng-class="{on:isAutoload}" class="autoload" title="Automatically load Term Info?"><span>Autoload</span></a>
</div>
<p ng-show="showTerms && noTerms" class="status">Sorry, no Term Info available :(</p>
<div ng-show="showTerms && termInfo.topTerms" class="topterms-holder">
<form>
<p class="head">
<input type="text" ng-model="topTermsCount" ng-change="loadTermInfo()">
<a class="max-holder" ng-click="loadAllTopTerms()" title="Load all Top-Terms">/<span class="max">{{termInfo.maxTerms | number}}</span></a> Top-Terms:
<a id="query_link" href="#/{{core}}/query?q={{name}}:[* TO *]"><span>Query</span>&nbsp;</a>
</p>
</form>
<ul>
<li class="clearfix" ng-repeat="countGroup in termInfo.topTerms">
<p><span>{{countGroup.count}}</span></p>
<ul>
<li ng-repeat="term in countGroup.terms" ng-class="{odd:$odd}"><a href="#/{{core}}/query?q={{name}}:{{term}}">{{term}}</a></li>
</ul>
</li>
</ul>
</div>
<div ng-show="showTerms && termInfo.histogram" class="histogram-holder">
<p class="head">Histogram:</p>
<ul>
<li ng-repeat="row in termInfo.histogram" ng-class="{odd:$odd}">
<dl class="clearfix" style="width: {{(( row.value / termInfo.histogramMax ) * 100 )}}%;">
<dt><span>{{ row.key | number}}</span></dt>
<dd><span>{{ row.value | number }}</span></dd>
</dl>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="related">
<select id="type_or_name"
ng-model="fieldOrType"
chosen
data-placeholder="Please select ..."
ng-change="selectFieldOrType()"
ng-options="f.value as f.label group by f.group for f in fieldsAndTypes"></select>
<dl id="f-df-t">
<dt class="field" ng-class="{active: selectedType=='Field'}" ng-show="leftbar.fields">Field</dt>
<dd class="field" ng-class="{active: selectedType=='Field'}" ng-repeat="field in leftbar.fields"><a href="#/{{core}}/schema-browser?field={{field}}">{{field}}</a></dd>
<dt class="copyfield" ng-show="leftbar.copyFieldSources">Copied from</dt>
<dd class="copyfield" ng-repeat="field in leftbar.copyFieldSources"><a href="#/{{core}}/schema-browser?field={{field}}">{{field}}</a></dd>
<dt class="copyfield" ng-show="leftbar.copyFieldDests">Copied to</dt>
<dd class="copyfield" ng-repeat="field in leftbar.copyFieldDests"><a href="#/{{core}}/schema-browser?field={{field}}">{{field}}</a></dd>
<dt class="dynamic-field" ng-class="{active: selectedType=='Dynamic Field'}" ng-show="leftbar.dynamicFields">Dynamic Field {{dynamicFields}} / {{dynamicFields.length()}}</dt>
<dd class="dynamic-field" ng-class="{active: selectedType=='Dynamic Field'}" ng-repeat="field in leftbar.dynamicFields"><a href="#/{{core}}/schema-browser?dynamic-field={{field}}">{{field}}</a></dd>
<dt class="type" ng-class="{active: selectedType=='Type'}" ng-show="leftbar.types">Type</dt>
<dd class="type" ng-class="{active: selectedType=='Type'}" ng-repeat="type in leftbar.types"><a href="#/{{core}}/schema-browser?type={{type}}">{{type}}</a></dd>
</dl>
<dl class="ukf-dsf">
<dt class="unique-key-field" ng-class="{active: isUniqueKeyField}" ng-show="uniqueKeyField">Unique Key Field</dt>
<dd class="unique-key-field" ng-class="{active: isUniqueKeyField}"><a ng-href="#/{{core}}/schema-browser?field={{uniqueKeyField}}">{{uniqueKeyField}}</a></dd>
<dt class="default-search-field" ng-class="{active: isDefaultSearchField}" ng-show="defaultSearchField">Default Search Field</dt>
<dd class="default-search-field" ng-class="{active: isDefaultSearchField}"><a ng-href="#/{{core}}/schema-browser?field={{defaultSearchField}}">{{defaultSearchField}}</a></dd>
</dl>
</div>
</div>
</div>

View File

@ -0,0 +1,99 @@
<!--
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.
-->
<div id="segments">
<div class="clearfix">
<div class="block fieldlist" id="statistics">
<h2><span>Segments</span></h2>
<p id="auto-refresh"><a ng-click="toggleAutoRefresh()" ng-class="{on:autorefresh}">Auto-Refresh</a></p>
<a class="reload" ng-click="refresh()"><span>reload</span></a>
<div class="message-container">
<div class="message"></div>
</div>
<div class="content">
<div id="result">
<div id="response">
<div class="segments-holder">
<ul>
<li>
<dl class="clearfix" style="width:100%;">
<dt>
<div>Size</div>
</dt>
<dd>
<div class="start">0</div>
<div class="w5" ng-repeat="x in xaxis">
<span ng-show="x&gt;0.001">{{x.value}}</span>
<span ng-hide="x&gt;0.001">&nbsp;</span>
</div>
<div class="end">{{segmentMB | number}} MB</div>
</dd>
</dl>
</li>
<li ng-repeat="segment in segments">
<dl class="clearfix" ng-style="{width: segment.totalSize+'%'}">
<dt>
<div>{{ segment.name }}</div>
</dt>
<dd>
<div class="live" ng-class="{'merge-candidate':segment.mergeCandidate}"
ng-style="{width: segment.aliveDocSize+'%'}">&nbsp;</div>
<div class="tooltip">
<div>Segment <b>{{segment.name}}</b>:</div>
<div class="label">#docs:</div>
<div>{{ segment.size | number }}</div>
<div class="label">#dels:</div>
<div>{{ segment.delCount | number }}</div>
<div class="label">size:</div>
<div>{{ segment.sizeInBytes | number }} bytes</div>
<div class="label">age:</div>
<div>{{ segment.age }}</div>
<div class="label">source:</div>
<div>{{ segment.source }}</div>
</div>
<div class="deleted" ng-show="segment.deletedDocSize"
style="width: {{ segment.deletedDocSize }}%; margin-left:{{ segment.aliveDocSize}}%;">
&nbsp;</div>
</dd>
</dl>
</li>
<li>
<dl>
<dt></dt>
<dd>Deletions: {{ deletionsPercentage }}%</dd>
</dl>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>