Fixes grunt watches, Fixes: U4-3138 Examine mgmt dashboard styling is broken, rebuilds the mgmt dashboard in angular
This commit is contained in:
@@ -193,12 +193,7 @@ module.exports = function (grunt) {
|
||||
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' },
|
||||
{ dest: '<%= vsdir %>/preview', src: '**', expand: true, cwd: '<%= distdir %>/preview' }
|
||||
]
|
||||
},
|
||||
vsLibs: {
|
||||
files: [
|
||||
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' }
|
||||
]
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
files: [{ dest: '<%= vsdir %>/../App_Plugins', src : '**', expand: true, cwd: 'src/packages/' }]
|
||||
}
|
||||
@@ -347,7 +342,7 @@ module.exports = function (grunt) {
|
||||
|
||||
watch:{
|
||||
css: {
|
||||
files: '**/*.less',
|
||||
files: 'src/**/*.less',
|
||||
tasks: ['watch-less', 'timestamp'],
|
||||
options: {
|
||||
livereload: true,
|
||||
@@ -374,15 +369,17 @@ module.exports = function (grunt) {
|
||||
tasks:['watch-html','timestamp']
|
||||
},
|
||||
|
||||
packages: {
|
||||
files: 'src/packages/**/*.*',
|
||||
tasks: ['watch-packages', 'timestamp'],
|
||||
},
|
||||
//SD: Removing package watching, we don't even use these anymore and they should be removed, the more watching we do the slower this gets
|
||||
//packages: {
|
||||
// files: 'src/packages/**/*.*',
|
||||
// tasks: ['watch-packages', 'timestamp'],
|
||||
//}
|
||||
|
||||
docs: {
|
||||
files: ['src/**/*.js', 'src/*.js'],
|
||||
tasks: ['docs:api'],
|
||||
}
|
||||
//SD: Removing watch docs, this gets run with the normal watching which we do not want
|
||||
//docs: {
|
||||
// files: ['src/**/*.js', 'src/*.js'],
|
||||
// tasks: ['docs:api'],
|
||||
//}
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
* @param {Array} queryStrings An array of key/value pairs
|
||||
*/
|
||||
dictionaryToQueryString: function (queryStrings) {
|
||||
|
||||
|
||||
if (angular.isArray(queryStrings)) {
|
||||
return _.map(queryStrings, function (item) {
|
||||
@@ -35,15 +34,13 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
return encodeURIComponent(key) + "=" + encodeURIComponent(val);
|
||||
}).join("&");
|
||||
}
|
||||
else if (angular.isObject(queryStrings)) {
|
||||
|
||||
/*
|
||||
//if we have a simple object, we can simply map with $.param
|
||||
//but with the current structure we cant since an array is an object and an object is an array
|
||||
if(angular.isObject(queryStrings)){
|
||||
return decodeURIComponent($.param(queryStrings));
|
||||
}*/
|
||||
|
||||
throw "The queryString parameter is not an array of key value pairs";
|
||||
//this allows for a normal object to be passed in (ie. a dictionary)
|
||||
return decodeURIComponent($.param(queryStrings));
|
||||
}
|
||||
|
||||
throw "The queryString parameter is not an array or object of key value pairs";
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<div id="examineManagement" ng-controller="Umbraco.Dashboard.ExamineMgmtController">
|
||||
|
||||
<h3>Examine Management</h3>
|
||||
|
||||
<div ng-show="loading">
|
||||
Loading...
|
||||
</div>
|
||||
|
||||
<h4>Indexers</h4>
|
||||
|
||||
<ul ng-hide="loading">
|
||||
<li class="provider" ng-repeat="indexer in indexerDetails">
|
||||
|
||||
<a href="" ng-click="toggle(indexer, 'showProperties')">
|
||||
{{indexer.name}}
|
||||
</a>
|
||||
|
||||
<ul ng-show="indexer.showProperties">
|
||||
|
||||
<li>
|
||||
|
||||
<a href="" ng-click="toggle(indexer, 'showTools')">Index info & tools</a>
|
||||
|
||||
<div ng-show="indexer.showTools && indexer.isLuceneIndex">
|
||||
<div>
|
||||
<br />
|
||||
<div ng-show="!indexer.isProcessing && (!indexer.processingAttempts || indexer.processingAttempts < 100)" class="btn-group">
|
||||
|
||||
<button class="btn btn-warning" ng-click="rebuildIndex(indexer)">Rebuild index</button>
|
||||
<button class="btn btn-warning" ng-click="optimizeIndex(indexer)" ng-show="indexer.documentCount > 0">Optimize index</button>
|
||||
</div>
|
||||
<div ng-show="indexer.isProcessing" class="progress progress-striped active">
|
||||
<div class="bar" style="width: 100%;"></div>
|
||||
</div>
|
||||
<div class="error" ng-show="indexer.processingAttempts >= 100">
|
||||
The process is taking longer than expected, check the umbraco log to see if there have been any errors during this operation
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<caption> </caption>
|
||||
<tr>
|
||||
<th>Documents in index</th>
|
||||
<td>{{indexer.documentCount}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Fields in index</th>
|
||||
<td>{{indexer.fieldCount}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Has deletions?</th>
|
||||
<td>
|
||||
<span>{{indexer.deletionCount > 0}}</span>
|
||||
(<span>{{indexer.deletionCount}}</span>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Optimized?</th>
|
||||
<td>
|
||||
<span>{{indexer.isOptimized}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li ng-show="indexer.indexCriteria.IncludeNodeTypes.length > 0 || indexer.indexCriteria.ExcludeNodeTypes.length > 0 || indexer.indexCriteria.ParentNodeId">
|
||||
<a href="" ng-click="toggle(indexer, 'showNodeTypes')">Node types</a>
|
||||
<table ng-show="indexer.showNodeTypes" class="table table-bordered table-condensed">
|
||||
<tr ng-show="indexer.indexCriteria.IncludeNodeTypes.length > 0">
|
||||
<th>Include node types</th>
|
||||
<td>{{indexer.indexCriteria.IncludeNodeTypes | json}}</td>
|
||||
</tr>
|
||||
<tr ng-show="indexer.indexCriteria.ExcludeNodeTypes.length > 0">
|
||||
<th>Exclude node types</th>
|
||||
<td>{{indexer.indexCriteria.ExcludeNodeTypes | json}}</td>
|
||||
</tr>
|
||||
<tr ng-show="indexer.indexCriteria.ParentNodeId">
|
||||
<th>Parent node id</th>
|
||||
<td>{{indexer.indexCriteria.ParentNodeId}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
|
||||
<li ng-show="indexer.indexCriteria.StandardFields.length > 0">
|
||||
<a href="" ng-click="toggle(indexer, 'showSystemFields')">System fields</a>
|
||||
<table ng-show="indexer.showSystemFields" class="table table-bordered table-condensed">
|
||||
<caption> </caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Enable sorting</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="field in indexer.indexCriteria.StandardFields">
|
||||
<th>{{field.Name}}</th>
|
||||
<td>{{field.EnableSorting}}</td>
|
||||
<td>{{field.Type}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
|
||||
<li ng-show="indexer.indexCriteria.UserFields.length > 0">
|
||||
<a href="" ng-click="toggle(indexer, 'showUserFields')">User fields</a>
|
||||
<table ng-show="indexer.showUserFields" class="table table-bordered table-condensed">
|
||||
<caption> </caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Enable sorting</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="field in indexer.indexCriteria.UserFields">
|
||||
<th>{{field.Name}}</th>
|
||||
<td>{{field.EnableSorting}}</td>
|
||||
<td>{{field.Type}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="" ng-click="toggle(indexer, 'showProviderProperties')">Provider properties</a>
|
||||
<table ng-show="indexer.showProviderProperties" class="table table-bordered table-condensed">
|
||||
<caption> </caption>
|
||||
<tr ng-repeat="(key, val) in indexer.providerProperties track by $index">
|
||||
<th>{{key}}</th>
|
||||
<td>{{val}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<h4>Searchers</h4>
|
||||
|
||||
<ul ng-hide="loading">
|
||||
<li class="provider" ng-repeat="searcher in searcherDetails">
|
||||
<a href="" ng-click="toggle(searcher, 'showProperties')">
|
||||
{{searcher.name}}
|
||||
</a>
|
||||
|
||||
<ul ng-show="searcher.showProperties">
|
||||
|
||||
<li class="search-tools">
|
||||
|
||||
<a href="" ng-click="toggle(searcher, 'showTools')">Search tools</a>
|
||||
|
||||
<div ng-show="searcher.showTools">
|
||||
<a class="hide" href="" ng-click="closeSearch(searcher)" ng-show="searcher.isSearching">Hide search results</a>
|
||||
|
||||
<br />
|
||||
|
||||
<form>
|
||||
|
||||
<div class="row form-search">
|
||||
<div class="span8 input-append">
|
||||
<input type="text" class="search-query" ng-model="searcher.searchText" />
|
||||
<button type="submit" class="btn btn-info" ng-click="search(searcher)" ng-disabled="searcher.isProcessing">Search</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label for="textSearch" class="radio inline">
|
||||
<input type="radio" name="searchType" id="textSearch" value="text" ng-model="searcher.searchType" />
|
||||
Text Search
|
||||
</label>
|
||||
<label for="luceneSearch" class="radio inline">
|
||||
<input type="radio" name="searchType" id="luceneSearch" value="lucene" ng-model="searcher.searchType" />
|
||||
Lucene Search
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<div class="search-results" ng-show="searcher.isSearching">
|
||||
|
||||
<div ng-show="indexer.isProcessing" class="progress progress-striped active">
|
||||
<div class="bar" style="width: 100%;"></div>
|
||||
</div>
|
||||
<table ng-hide="searcher.isProcessing" class="table table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="score">Score</th>
|
||||
<th class="id">Id</th>
|
||||
<th>Values</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="result in searcher.searchResults">
|
||||
<td>{{result.Score}}</td>
|
||||
<td>{{result.Id}}</td>
|
||||
<td>
|
||||
<span ng-repeat="(key,val) in result.Fields track by $index">
|
||||
<span class=""><em>{{key}}</em>:</span>
|
||||
<span class="text-info">{{val}}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="" ng-click="toggle(searcher, 'showProviderProperties')">Provider properties</a>
|
||||
<table ng-show="searcher.showProviderProperties" class="table table-bordered table-condensed">
|
||||
<caption> </caption>
|
||||
<tr ng-repeat="(key, val) in searcher.providerProperties track by $index">
|
||||
<th>{{key}}</th>
|
||||
<td>{{val}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,144 @@
|
||||
function examineMgmtController($scope, umbRequestHelper, $log, $http, $q) {
|
||||
|
||||
$scope.indexerDetails = [];
|
||||
$scope.searcherDetails = [];
|
||||
$scope.loading = true;
|
||||
|
||||
function checkProcessing(indexer, checkActionName) {
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", checkActionName, { indexerName: indexer.name })),
|
||||
'Failed to check index processing')
|
||||
.then(function(data) {
|
||||
|
||||
if (data) {
|
||||
|
||||
//copy all resulting properties
|
||||
for (var k in data) {
|
||||
indexer[k] = data[k];
|
||||
}
|
||||
indexer.isProcessing = false;
|
||||
}
|
||||
else {
|
||||
setTimeout(function() {
|
||||
//don't continue if we've tried 100 times
|
||||
if (indexer.processingAttempts < 100) {
|
||||
checkProcessing(indexer, checkActionName);
|
||||
//add an attempt
|
||||
indexer.processingAttempts++;
|
||||
}
|
||||
else {
|
||||
//we've exceeded 100 attempts, stop processing
|
||||
indexer.isProcessing = false;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.search = function (searcher, e) {
|
||||
if (e && e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "GetSearchResults", {
|
||||
searcherName: searcher.name,
|
||||
query: searcher.searchText,
|
||||
queryType: searcher.searchType
|
||||
})),
|
||||
'Failed to search')
|
||||
.then(function(searchResults) {
|
||||
searcher.isSearching = true;
|
||||
searcher.searchResults = searchResults;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggle = function(provider, propName) {
|
||||
if (provider[propName] !== undefined) {
|
||||
provider[propName] = !provider[propName];
|
||||
}
|
||||
else {
|
||||
provider[propName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.rebuildIndex = function(indexer) {
|
||||
if (confirm("This will cause the index to be rebuilt. " +
|
||||
"Depending on how much content there is in your site this could take a while. " +
|
||||
"It is not recommended to rebuild an index during times of high website traffic " +
|
||||
"or when editors are editing content.")) {
|
||||
indexer.isProcessing = true;
|
||||
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "PostRebuildIndex", { indexerName: indexer.name })),
|
||||
'Failed to rebuild index')
|
||||
.then(function () {
|
||||
|
||||
//rebuilding has started, nothing is returned accept a 200 status code.
|
||||
//lets poll to see if it is done.
|
||||
setTimeout(function () {
|
||||
checkProcessing(indexer, "PostCheckRebuildIndex");
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.optimizeIndex = function(indexer) {
|
||||
if (confirm("This will cause the index to be optimized which will improve its performance. " +
|
||||
"It is not recommended to optimize an index during times of high website traffic " +
|
||||
"or when editors are editing content.")) {
|
||||
indexer.isProcessing = true;
|
||||
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "PostOptimizeIndex", { indexerName: indexer.name })),
|
||||
'Failed to optimize index')
|
||||
.then(function () {
|
||||
|
||||
//optimizing has started, nothing is returned accept a 200 status code.
|
||||
//lets poll to see if it is done.
|
||||
setTimeout(function () {
|
||||
checkProcessing(indexer, "PostCheckOptimizeIndex");
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.closeSearch = function(searcher) {
|
||||
searcher.isSearching = true;
|
||||
}
|
||||
|
||||
|
||||
//go get the data
|
||||
|
||||
//combine two promises and execute when they are both done
|
||||
$q.all([
|
||||
|
||||
//get the indexer details
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "GetIndexerDetails")),
|
||||
'Failed to retrieve indexer details')
|
||||
.then(function(data) {
|
||||
$scope.indexerDetails = data;
|
||||
}),
|
||||
|
||||
//get the searcher details
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "GetSearcherDetails")),
|
||||
'Failed to retrieve searcher details')
|
||||
.then(function(data) {
|
||||
$scope.searcherDetails = data;
|
||||
for (var s in $scope.searcherDetails) {
|
||||
$scope.searcherDetails[s].searchType = "text";
|
||||
}
|
||||
})
|
||||
|
||||
]).then(function () {
|
||||
//all init loading is complete
|
||||
$scope.loading = false;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.ExamineMgmtController", examineMgmtController);
|
||||
@@ -844,9 +844,6 @@
|
||||
<Content Include="Umbraco_Client\CodeMirror\Js\Theme\xq-dark.css" />
|
||||
<Content Include="Umbraco_Client\ContextMenu\Css\jquery.contextMenu.css" />
|
||||
<Content Include="Umbraco_Client\ContextMenu\Js\jquery.contextMenu.js" />
|
||||
<Content Include="Umbraco_Client\Dashboards\ExamineManagement.css" />
|
||||
<Content Include="Umbraco_Client\Dashboards\ExamineManagement.js" />
|
||||
<Content Include="Umbraco_Client\Dashboards\ExamineManagementIco.png" />
|
||||
<Content Include="Umbraco_Client\Dialogs\SortDialog.css" />
|
||||
<Content Include="Umbraco_client\Dialogs\SortDialog.js" />
|
||||
<Content Include="Umbraco_Client\Dialogs\AssignDomain2.js" />
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
</control>
|
||||
</tab>
|
||||
<tab caption="Examine Management">
|
||||
<control>/umbraco/dashboard/ExamineManagement.ascx</control>
|
||||
<control>
|
||||
views/dashboard/developer/examinemanagement.html
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
</control>
|
||||
</tab>
|
||||
<tab caption="Examine Management">
|
||||
<control>/umbraco/dashboard/ExamineManagement.ascx</control>
|
||||
<control>
|
||||
views/dashboard/developer/examinemanagement.html
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
#examineManagement .provider
|
||||
{
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
#examineManagement .propertyPane
|
||||
{
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#examineManagement table th
|
||||
{
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#examineManagement table td
|
||||
{
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#examineManagement table td.highlight
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#examineManagement .propertyPane > a
|
||||
{
|
||||
padding: 3px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#examineManagement .propertyPane > a.expanded
|
||||
{
|
||||
border-bottom: 1px solid #CCC;
|
||||
margin-bottom: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#examineManagement .provider > a
|
||||
{
|
||||
padding: 7px;
|
||||
display: block;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#examineManagement .provider > div
|
||||
{
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
#examineManagement a
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#examineManagement a:hover
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#examineManagement .index-tools table
|
||||
{
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
#examineManagement .index-tools .index-actions
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
#examineManagement .index-tools .index-actions .error
|
||||
{
|
||||
width: 560px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools input[type="text"]
|
||||
{
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools a.hide
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools .search-results
|
||||
{
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools .search-results table
|
||||
{
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools .search-results th.score
|
||||
{
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools .search-results th.id
|
||||
{
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
#examineManagement .search-tools .search-results tbody tr td
|
||||
{
|
||||
border-bottom: 1px solid #DDD;
|
||||
padding: 3px;
|
||||
}
|
||||
#examineManagement .search-tools .search-results tbody tr td span.key {
|
||||
display: inline-block;
|
||||
color: rgb(0, 64, 201);
|
||||
font-style: italic;
|
||||
}
|
||||
#examineManagement .search-tools .search-results tbody tr td span.value {
|
||||
font-weight: normal;
|
||||
display: inline-block;
|
||||
padding-right: 5px;
|
||||
color: black;
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
Umbraco.Sys.registerNamespace("Umbraco.Dashboards");
|
||||
|
||||
(function ($) {
|
||||
|
||||
Umbraco.Dashboards.ExamineManagement = base2.Base.extend({
|
||||
|
||||
//private methods/variables
|
||||
_opts: null,
|
||||
_koViewModel: null,
|
||||
|
||||
_mapSearcherModelProperties: function (indexerModel) {
|
||||
var self = this;
|
||||
|
||||
var viewModel = self._mapBaseProviderModelProperties(indexerModel);
|
||||
|
||||
//add custom searcher props
|
||||
viewModel.searchText = ko.observable("");
|
||||
viewModel.searchType = ko.observable("text");
|
||||
viewModel.isSearching = ko.observable(false);
|
||||
viewModel.closeSearch = function() {
|
||||
this.isSearching(false);
|
||||
};
|
||||
//add flag properties to determine if either button has been pressed
|
||||
viewModel.isProcessing = ko.observable(false);
|
||||
//don't need an observable array since it does not change, just need an observable to hold an array.
|
||||
viewModel.searchResults = ko.observable([]);
|
||||
viewModel.search = function () {
|
||||
//NOTE: 'this' is the ko view model
|
||||
this.isSearching(true);
|
||||
self._doSearch(this);
|
||||
};
|
||||
viewModel.handleEnter = function(vm, event) {
|
||||
var keyCode = (event.which ? event.which : event.keyCode);
|
||||
if (keyCode === 13) {
|
||||
vm.search();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
return viewModel;
|
||||
},
|
||||
|
||||
_mapBaseProviderModelProperties : function(indexerModel) {
|
||||
var self = this;
|
||||
|
||||
//do the ko auto-mapping
|
||||
var viewModel = ko.mapping.fromJS(indexerModel);
|
||||
|
||||
//need to re-map the dictionary to an array so we can bind to it
|
||||
//we don't need to have an observable array since we're never adding/removing, just setting the object
|
||||
viewModel.ProviderProperties = ko.observable(self._mapDictionaryToArray(indexerModel.ProviderProperties));
|
||||
|
||||
//add toggle and show properties
|
||||
//(NOTE that 'this' inside of these functions is actually the knockoutjs model that is bound)
|
||||
viewModel.showProperties = ko.observable(false);
|
||||
viewModel.toggleProperties = function () {
|
||||
this.showProperties(!this.showProperties());
|
||||
};
|
||||
viewModel.showProviderProperties = ko.observable(false);
|
||||
viewModel.toggleProviderProperties = function () {
|
||||
this.showProviderProperties(!this.showProviderProperties());
|
||||
};
|
||||
viewModel.showTools = ko.observable(false);
|
||||
viewModel.toggleTools = function () {
|
||||
this.showTools(!this.showTools());
|
||||
};
|
||||
|
||||
return viewModel;
|
||||
},
|
||||
|
||||
_mapIndexerModelProperties: function (indexerModel, viewModel) {
|
||||
var self = this;
|
||||
|
||||
//if we are updating the view model or creating it for the first time.
|
||||
var isUpdate = viewModel != null;
|
||||
|
||||
if (!isUpdate) {
|
||||
//do the ko auto-mapping to the new object and create additional properties
|
||||
|
||||
viewModel = self._mapBaseProviderModelProperties(indexerModel);
|
||||
|
||||
//property to track how many attempts have been made to check if the index is optimized or rebuilt
|
||||
viewModel.processingAttempts = ko.observable(0);
|
||||
//add a hasDeletions prop
|
||||
viewModel.hasDeletions = ko.observable(indexerModel.DeletionCount > 0);
|
||||
//add toggle and show properties
|
||||
//(NOTE that 'this' inside of these functions is actually the knockoutjs model that is bound)
|
||||
viewModel.showSystemFields = ko.observable(false);
|
||||
viewModel.toggleSystemFields = function () {
|
||||
this.showSystemFields(!this.showSystemFields());
|
||||
};
|
||||
viewModel.showUserFields = ko.observable(false);
|
||||
viewModel.toggleUserFields = function () {
|
||||
this.showUserFields(!this.showUserFields());
|
||||
};
|
||||
viewModel.showNodeTypes = ko.observable(false);
|
||||
viewModel.toggleNodeTypes = function () {
|
||||
this.showNodeTypes(!this.showNodeTypes());
|
||||
};
|
||||
//add flag properties to determine if either button has been pressed
|
||||
viewModel.isProcessing = ko.observable(false);
|
||||
//add the button methods
|
||||
viewModel.rebuildIndex = function () {
|
||||
if (confirm("This will cause the index to be rebuilt. " +
|
||||
"Depending on how much content there is in your site this could take a while. " +
|
||||
"It is not recommended to rebuild an index during times of high website traffic " +
|
||||
"or when editors are editing content.")) {
|
||||
//NOTE: 'this' is the knockoutjs model that is bound
|
||||
self._doProcessing(this.Name(), this, "PostRebuildIndex", "PostCheckRebuildIndex");
|
||||
}
|
||||
};
|
||||
viewModel.optimizeIndex = function () {
|
||||
if (confirm("This will cause the index to be optimized which will improve its performance. " +
|
||||
"It is not recommended to optimize an index during times of high website traffic " +
|
||||
"or when editors are editing content.")) {
|
||||
//NOTE: 'this' is the knockoutjs model that is bound
|
||||
self._doProcessing(this.Name(), this, "PostOptimizeIndex", "PostCheckOptimizeIndex");
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
//update it with new data
|
||||
ko.mapping.fromJS(indexerModel, viewModel);
|
||||
}
|
||||
|
||||
//whether we are updating or creating we always execute this logic...
|
||||
|
||||
//change the include/exclude node types to say something different if they are empty
|
||||
viewModel.IndexCriteria.IncludeNodeTypes(indexerModel.IndexCriteria.IncludeNodeTypes.join());
|
||||
viewModel.IndexCriteria.ExcludeNodeTypes(indexerModel.IndexCriteria.ExcludeNodeTypes.join());
|
||||
if (viewModel.IndexCriteria.IncludeNodeTypes() == "")
|
||||
viewModel.IndexCriteria.IncludeNodeTypes("Include all");
|
||||
if (viewModel.IndexCriteria.ExcludeNodeTypes() == "")
|
||||
viewModel.IndexCriteria.ExcludeNodeTypes("Exclude none");
|
||||
|
||||
return viewModel;
|
||||
},
|
||||
|
||||
_doSearch: function(viewModel) {
|
||||
var self = this;
|
||||
viewModel.isProcessing(true);
|
||||
$.get(self._opts.restServiceLocation + "GetSearchResults?searcherName=" + viewModel.Name() + "&query=" + viewModel.searchText() + "&queryType=" + viewModel.searchType(),
|
||||
function(searchResults) {
|
||||
viewModel.isProcessing(false);
|
||||
//re-map the fields dictionary to array
|
||||
for (var s in searchResults) {
|
||||
searchResults[s].Fields = self._mapDictionaryToArray(searchResults[s].Fields);
|
||||
}
|
||||
viewModel.searchResults(searchResults);
|
||||
}).fail(function(a, b, c) {
|
||||
alert(b + ": " + a.responseText);
|
||||
});
|
||||
},
|
||||
|
||||
_doProcessing: function (name, viewModel, processingActionName, pollActionName) {
|
||||
var self = this;
|
||||
viewModel.isProcessing(true); //set the model processing
|
||||
|
||||
$.post(self._opts.restServiceLocation + processingActionName + "?indexerName=" + name,
|
||||
function (data) {
|
||||
|
||||
//optimization has started, nothing is returned accept a 200 status code.
|
||||
//lets poll to see if it is done.
|
||||
setTimeout(function() {
|
||||
self._checkProcessing(name, viewModel, pollActionName);
|
||||
}, 1000);
|
||||
|
||||
}).fail(function (a, b, c) {
|
||||
alert(b + ": " + a.responseText);
|
||||
});
|
||||
},
|
||||
|
||||
_checkProcessing: function (name, viewModel, actionName) {
|
||||
var self = this;
|
||||
|
||||
$.post(self._opts.restServiceLocation + actionName + "?indexerName=" + name,
|
||||
function (data) {
|
||||
if (data) {
|
||||
//success! now, we need to re-update the whole indexer model
|
||||
self._mapIndexerModelProperties(data, viewModel);
|
||||
viewModel.isProcessing(false);
|
||||
}
|
||||
else {
|
||||
//copy local from closure
|
||||
var vm = viewModel;
|
||||
var an = actionName;
|
||||
setTimeout(function () {
|
||||
//don't continue if we've tried 100 times
|
||||
if (vm.processingAttempts() < 100) {
|
||||
self._checkProcessing(name, vm, an);
|
||||
//add an attempt
|
||||
vm.processingAttempts(vm.processingAttempts() + 1);
|
||||
}
|
||||
else {
|
||||
//we've exceeded 100 attempts, stop processing
|
||||
viewModel.isProcessing(false);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}).fail(function (a, b, c) {
|
||||
alert(b + ": " + a.responseText);
|
||||
});
|
||||
},
|
||||
|
||||
_mapDictionaryToArray: function (dictionary) {
|
||||
var result = [];
|
||||
for (var key in dictionary) {
|
||||
if (dictionary.hasOwnProperty(key)) {
|
||||
result.push({ key: key, value: dictionary[key] });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
_loadDetails: function () {
|
||||
var self = this;
|
||||
self._koViewModel.loading(true);
|
||||
|
||||
var loadingCount = 2;
|
||||
|
||||
$.get(self._opts.restServiceLocation + "GetIndexerDetails",
|
||||
function (e) {
|
||||
if (--loadingCount == 0) {
|
||||
self._koViewModel.loading(false);
|
||||
}
|
||||
|
||||
//loop through each indexer in the array and remap its properties
|
||||
for (var item in e) {
|
||||
e[item] = self._mapIndexerModelProperties(e[item]);
|
||||
}
|
||||
|
||||
self._koViewModel.indexerDetails(e);
|
||||
}).fail(function (a, b, c) {
|
||||
alert(b + ": " + a.responseText);
|
||||
});
|
||||
|
||||
$.get(self._opts.restServiceLocation + "GetSearcherDetails",
|
||||
function (e) {
|
||||
if (--loadingCount == 0) {
|
||||
self._koViewModel.loading(false);
|
||||
}
|
||||
|
||||
for (var item in e) {
|
||||
e[item] = self._mapSearcherModelProperties(e[item]);
|
||||
}
|
||||
|
||||
self._koViewModel.searcherDetails(e);
|
||||
}).fail(function (a, b, c) {
|
||||
alert(b + ": " + a.responseText);
|
||||
});
|
||||
},
|
||||
|
||||
// Constructor
|
||||
constructor: function (opts) {
|
||||
// Merge options with default
|
||||
this._opts = $.extend({
|
||||
container: $("#examineManagement")
|
||||
}, opts);
|
||||
},
|
||||
|
||||
//public methods/variables
|
||||
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
//The knockout js view model for the selected item
|
||||
self._koViewModel = {
|
||||
indexerDetails: ko.observable(null),
|
||||
searcherDetails: ko.observable(null),
|
||||
loading: ko.observable(false)
|
||||
};
|
||||
|
||||
ko.applyBindings(self._koViewModel, self._opts.container.get(0));
|
||||
|
||||
this._loadDetails();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
//Set defaults for jQuery ajax calls.
|
||||
$.ajaxSetup({
|
||||
dataType: 'json',
|
||||
cache: false,
|
||||
contentType: 'application/json; charset=utf-8'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -217,6 +217,10 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
"tagsDataBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TagsDataController>(
|
||||
controller => controller.GetTags(""))
|
||||
},
|
||||
{
|
||||
"examineMgmtBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ExamineManagementApiController>(
|
||||
controller => controller.GetIndexerDetails())
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,35 +1,44 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Examine;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
{
|
||||
|
||||
[DataContract(Name = "indexer", Namespace = "")]
|
||||
public class ExamineIndexerModel : ExamineSearcherModel
|
||||
{
|
||||
[DataMember(Name = "indexCriteria")]
|
||||
public IIndexCriteria IndexCriteria { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of docs in the index
|
||||
/// </summary>
|
||||
[DataMember(Name = "documentCount")]
|
||||
public int DocumentCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of fields in the index
|
||||
/// </summary>
|
||||
[DataMember(Name = "fieldCount")]
|
||||
public int FieldCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of documents flagged for deletion in the index
|
||||
/// </summary>
|
||||
[DataMember(Name = "deletionCount")]
|
||||
public int DeletionCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the indexed is optimized
|
||||
/// </summary>
|
||||
[DataMember(Name = "isOptimized")]
|
||||
public bool IsOptimized{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generally will always be true unless someone has created a new non-lucene index
|
||||
/// </summary>
|
||||
[DataMember(Name = "isLuceneIndex")]
|
||||
public bool IsLuceneIndex { get; set; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
{
|
||||
[DataContract(Name = "searcher", Namespace = "")]
|
||||
public class ExamineSearcherModel
|
||||
{
|
||||
public ExamineSearcherModel()
|
||||
@@ -12,7 +14,10 @@ namespace Umbraco.Web.Search
|
||||
ProviderProperties = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "providerProperties")]
|
||||
public IDictionary<string, string> ProviderProperties { get; private set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Web.WebServices
|
||||
};
|
||||
var props = TypeHelper.CachedDiscoverableProperties(searcher.GetType(), mustWrite: false)
|
||||
//ignore these properties
|
||||
.Where(x => !new[] { "Description" }.InvariantContains(x.Name))
|
||||
.Where(x => new[] {"Description"}.InvariantContains(x.Name) == false)
|
||||
.OrderBy(x => x.Name);
|
||||
foreach (var p in props)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ namespace Umbraco.Web.WebServices
|
||||
/// <param name="indexerName"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is kind of rudementary since there's no way we can know that the index has rebuilt, we'll just check
|
||||
/// This is kind of rudimentary since there's no way we can know that the index has rebuilt, we'll just check
|
||||
/// if the index is locked based on Lucene apis
|
||||
/// </remarks>
|
||||
public ExamineIndexerModel PostCheckRebuildIndex(string indexerName)
|
||||
@@ -181,7 +181,7 @@ namespace Umbraco.Web.WebServices
|
||||
};
|
||||
var props = TypeHelper.CachedDiscoverableProperties(indexer.GetType(), mustWrite: false)
|
||||
//ignore these properties
|
||||
.Where(x => !new[] { "IndexerData", "Description", "WorkingFolder" }.InvariantContains(x.Name))
|
||||
.Where(x => new[] {"IndexerData", "Description", "WorkingFolder"}.InvariantContains(x.Name) == false)
|
||||
.OrderBy(x => x.Name);
|
||||
foreach (var p in props)
|
||||
{
|
||||
@@ -193,7 +193,7 @@ namespace Umbraco.Web.WebServices
|
||||
{
|
||||
indexerModel.IsLuceneIndex = true;
|
||||
indexerModel.DocumentCount = luceneIndexer.GetIndexDocumentCount();
|
||||
indexerModel.FieldCount = luceneIndexer.GetIndexDocumentCount();
|
||||
indexerModel.FieldCount = luceneIndexer.GetIndexFieldCount();
|
||||
indexerModel.IsOptimized = luceneIndexer.IsIndexOptimized();
|
||||
indexerModel.DeletionCount = luceneIndexer.GetDeletedDocumentsCount();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user