Features. Added confirm popup when disabling a feature that other enabled features depend on.

This commit is contained in:
Piotr Szmyd
2014-02-10 21:56:49 +01:00
parent 185642d44b
commit f5779c9e89
8 changed files with 55 additions and 13 deletions

View File

@@ -179,8 +179,10 @@ namespace Orchard.Modules.Controllers {
Descriptor = f,
IsEnabled = _shellDescriptor.Features.Any(sf => sf.Name == f.Id),
IsRecentlyInstalled = _moduleService.IsRecentlyInstalled(f.Extension),
NeedsUpdate = featuresThatNeedUpdate.Contains(f.Id)
});
NeedsUpdate = featuresThatNeedUpdate.Contains(f.Id),
DependentFeatures = _moduleService.GetDependentFeatures(f.Id).Where(x => x.Id != f.Id).ToList()
})
.ToList();
return View(new FeaturesViewModel { Features = features });
}

View File

@@ -1,4 +1,6 @@
using Orchard.Environment.Extensions.Models;
using System.Collections;
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Modules.Models {
/// <summary>
@@ -29,5 +31,10 @@ namespace Orchard.Modules.Models {
/// Boolean value indicating if the feature was recently installed.
/// </summary>
public bool IsRecentlyInstalled { get; set; }
/// <summary>
/// List of features that depend on this feature.
/// </summary>
public IEnumerable<FeatureDescriptor> DependentFeatures { get; set; }
}
}

View File

@@ -41,13 +41,18 @@
var featureId = actionLink.data("feature-id");
var action = actionLink.data("feature-action");
var force = actionLink.data("feature-force");
var dependants = actionLink.data("feature-dependants");
$("[name='submit.BulkExecute']").val("yes");
$("[name='featureIds']").val(featureId);
$("[name='bulkAction']").val(action);
$("[name='force']").val(force);
if (!dependants || /^\s*$/.test(dependants) || confirm(confirmDisableMessage + "\n\n" + dependants)) {
$("[name='submit.BulkExecute']").val("yes");
$("[name='featureIds']").val(featureId);
$("[name='bulkAction']").val(action);
$("[name='force']").val(force);
actionLink.parents("form:first").submit();
}
actionLink.parents("form:first").submit();
e.preventDefault();
});
};

View File

@@ -1,2 +1,4 @@
$(function(){var n=function(){var n=$(".bulk-actions-wrapper").addClass("visible"),t=$(".switch-for-switchable");t.prepend(n),$("#search-box").focus().keyup(function(){var n=$(this).val(),t;if(n==""){$("li.category").show(),$("li.feature:hidden").show();return}$("li.feature").each(function(){var t=$(this),i=t.find("h3:first").text();i.toLowerCase().indexOf(n.toLowerCase())>=0?t.show():t.hide()}),$("li.category:hidden").show(),t=$("li.category:not(:has(li.feature:visible))").hide()})},t=function(){$("li.feature h3").on("change","input[type='checkbox']",function(){var n=$(this).is(":checked"),t=$(this).parents("li.feature:first");t.toggleClass("selected",n)})},i=function(){$("li.feature .actions").on("click","a[data-feature-action]",function(n){var t=$(this),i=t.data("feature-id"),r=t.data("feature-action"),u=t.data("feature-force");$("[name='submit.BulkExecute']").val("yes"),$("[name='featureIds']").val(i),$("[name='bulkAction']").val(r),$("[name='force']").val(u),t.parents("form:first").submit(),n.preventDefault()})};n(),t(),i()});
//@ sourceMappingURL=features.admin.min.js.map
$(function(){var n=function(){var n=$(".bulk-actions-wrapper").addClass("visible"),t=$(".switch-for-switchable");t.prepend(n);$("#search-box").focus().keyup(function(){var n=$(this).val(),t;if(n==""){$("li.category").show();$("li.feature:hidden").show();return}$("li.feature").each(function(){var t=$(this),i=t.find("h3:first").text();i.toLowerCase().indexOf(n.toLowerCase())>=0?t.show():t.hide()});$("li.category:hidden").show();t=$("li.category:not(:has(li.feature:visible))").hide()})},t=function(){$("li.feature h3").on("change","input[type='checkbox']",function(){var n=$(this).is(":checked"),t=$(this).parents("li.feature:first");t.toggleClass("selected",n)})},i=function(){$("li.feature .actions").on("click","a[data-feature-action]",function(n){var t=$(this),r=t.data("feature-id"),u=t.data("feature-action"),f=t.data("feature-force"),i=t.data("feature-dependants");(!i||/^\s*$/.test(i)||confirm(confirmDisableMessage+"\n\n"+i))&&($("[name='submit.BulkExecute']").val("yes"),$("[name='featureIds']").val(r),$("[name='bulkAction']").val(u),$("[name='force']").val(f),t.parents("form:first").submit());n.preventDefault()})};n();t();i()});
/*
//# sourceMappingURL=features.admin.min.js.map
*/

View File

@@ -2,7 +2,7 @@
"version":3,
"file":"features.admin.min.js",
"lineCount":1,
"mappings":"AAAAA,CAAC,CAAC,QAAQ,CAAA,CAAG,CAET,IAAIC,EAAuBA,QAAQ,CAAA,CAAG,CAClC,IAAIC,EAAcF,CAAC,CAAC,uBAAD,CAAyBG,SAAS,CAAC,SAAD,EACjDC,EAAYJ,CAAC,CAAC,wBAAD,CAD+C,CAEhEI,CAASC,QAAQ,CAACH,CAAD,CAAa,CAC9BF,CAAC,CAAC,aAAD,CAAeM,MAAM,CAAA,CAAEC,MAAM,CAAC,QAAQ,CAAA,CAAG,CACtC,IAAIC,EAAOR,CAAC,CAAC,IAAD,CAAMS,IAAI,CAAA,EAkBlBC,CAlBoB,CAExB,GAAIF,CAAK,EAAG,GAAI,CACZR,CAAC,CAAC,aAAD,CAAeW,KAAK,CAAA,CAAE,CACvBX,CAAC,CAAC,mBAAD,CAAqBW,KAAK,CAAA,CAAE,CAC7B,MAHY,CAMhBX,CAAC,CAAC,YAAD,CAAcY,KAAK,CAAC,QAAQ,CAAA,CAAG,CAC5B,IAAIC,EAAMb,CAAC,CAAC,IAAD,EACPc,EAAQD,CAAGE,KAAK,CAAC,UAAD,CAAYP,KAAK,CAAA,CADpB,CAEbM,CAAKE,YAAY,CAAA,CAAEC,QAAQ,CAACT,CAAIQ,YAAY,CAAA,CAAjB,CAAqB,EAAG,CAAvD,CACIH,CAAGF,KAAK,CAAA,CADZ,CAGIE,CAAGK,KAAK,CAAA,CANgB,CAAZ,CAOlB,CAEFlB,CAAC,CAAC,oBAAD,CAAsBW,KAAK,CAAA,CAAE,CAC1BD,CAAO,CAAEV,CAAC,CAAC,2CAAD,CAA6CkB,KAAK,CAAA,CAnB1B,CAAZ,CAJI,EA2BlCC,EAA8BA,QAAQ,CAAA,CAAG,CACzCnB,CAAC,CAAC,eAAD,CAAiBoB,GAAG,CAAC,QAAQ,CAAE,wBAAwB,CAAE,QAAQ,CAAA,CAAG,CACjE,IAAIC,EAAUrB,CAAC,CAAC,IAAD,CAAMsB,GAAG,CAAC,UAAD,EACpBC,EAAUvB,CAAC,CAAC,IAAD,CAAMwB,QAAQ,CAAC,kBAAD,CADO,CAEpCD,CAAOE,YAAY,CAAC,UAAU,CAAEJ,CAAb,CAH8C,CAAhD,CADoB,EAQzCK,EAAwBA,QAAQ,CAAA,CAAG,CACnC1B,CAAC,CAAC,qBAAD,CAAuBoB,GAAG,CAAC,OAAO,CAAE,wBAAwB,CAAE,QAAQ,CAACO,CAAD,CAAI,CACvE,IAAIC,EAAa5B,CAAC,CAAC,IAAD,EACd6B,EAAYD,CAAUE,KAAK,CAAC,YAAD,EAC3BC,EAASH,CAAUE,KAAK,CAAC,gBAAD,EACxBE,EAAQJ,CAAUE,KAAK,CAAC,eAAD,CAHH,CAKxB9B,CAAC,CAAC,6BAAD,CAA+BS,IAAI,CAAC,KAAD,CAAO,CAC3CT,CAAC,CAAC,qBAAD,CAAuBS,IAAI,CAACoB,CAAD,CAAW,CACvC7B,CAAC,CAAC,qBAAD,CAAuBS,IAAI,CAACsB,CAAD,CAAQ,CACpC/B,CAAC,CAAC,gBAAD,CAAkBS,IAAI,CAACuB,CAAD,CAAO,CAE9BJ,CAAUJ,QAAQ,CAAC,YAAD,CAAcS,OAAO,CAAA,CAAE,CACzCN,CAACO,eAAe,CAAA,CAZuD,CAAhD,CADQ,CAVtC,CA2BDjC,CAAoB,CAAA,CAAE,CACtBkB,CAA2B,CAAA,CAAE,CAC7BO,CAAqB,CAAA,CAxDZ,CAAZ,CAyDC",
"mappings":"AAAAA,CAAC,CAAC,QAAQ,CAAA,CAAG,CAET,IAAIC,EAAuB,QAAQ,CAAA,CAAG,CAClC,IAAIC,EAAcF,CAAC,CAAC,uBAAD,CAAyBG,SAAS,CAAC,SAAD,EACjDC,EAAYJ,CAAC,CAAC,wBAAD,CAD+C,CAEhEI,CAASC,QAAQ,CAACH,CAAD,CAAa,CAC9BF,CAAC,CAAC,aAAD,CAAeM,MAAM,CAAA,CAAEC,MAAM,CAAC,QAAQ,CAAA,CAAG,CACtC,IAAIC,EAAOR,CAAC,CAAC,IAAD,CAAMS,IAAI,CAAA,EAkBlBC,CAlBoB,CAExB,GAAIF,CAAK,EAAG,GAAI,CACZR,CAAC,CAAC,aAAD,CAAeW,KAAK,CAAA,CAAE,CACvBX,CAAC,CAAC,mBAAD,CAAqBW,KAAK,CAAA,CAAE,CAC7B,MAHY,CAMhBX,CAAC,CAAC,YAAD,CAAcY,KAAK,CAAC,QAAQ,CAAA,CAAG,CAC5B,IAAIC,EAAMb,CAAC,CAAC,IAAD,EACPc,EAAQD,CAAGE,KAAK,CAAC,UAAD,CAAYP,KAAK,CAAA,CADpB,CAEbM,CAAKE,YAAY,CAAA,CAAEC,QAAQ,CAACT,CAAIQ,YAAY,CAAA,CAAjB,CAAqB,EAAG,CAAvD,CACIH,CAAGF,KAAK,CAAA,CADZ,CAGIE,CAAGK,KAAK,CAAA,CANgB,CAAZ,CAOlB,CAEFlB,CAAC,CAAC,oBAAD,CAAsBW,KAAK,CAAA,CAAE,CAC1BD,CAAO,CAAEV,CAAC,CAAC,2CAAD,CAA6CkB,KAAK,CAAA,CAnB1B,CAAZ,CAJI,EA2BlCC,EAA8B,QAAQ,CAAA,CAAG,CACzCnB,CAAC,CAAC,eAAD,CAAiBoB,GAAG,CAAC,QAAQ,CAAE,wBAAwB,CAAE,QAAQ,CAAA,CAAG,CACjE,IAAIC,EAAUrB,CAAC,CAAC,IAAD,CAAMsB,GAAG,CAAC,UAAD,EACpBC,EAAUvB,CAAC,CAAC,IAAD,CAAMwB,QAAQ,CAAC,kBAAD,CADO,CAEpCD,CAAOE,YAAY,CAAC,UAAU,CAAEJ,CAAb,CAH8C,CAAhD,CADoB,EAQzCK,EAAwB,QAAQ,CAAA,CAAG,CACnC1B,CAAC,CAAC,qBAAD,CAAuBoB,GAAG,CAAC,OAAO,CAAE,wBAAwB,CAAE,QAAQ,CAACO,CAAD,CAAI,CACvE,IAAIC,EAAa5B,CAAC,CAAC,IAAD,EACd6B,EAAYD,CAAUE,KAAK,CAAC,YAAD,EAC3BC,EAASH,CAAUE,KAAK,CAAC,gBAAD,EACxBE,EAAQJ,CAAUE,KAAK,CAAC,eAAD,EACvBG,EAAaL,CAAUE,KAAK,CAAC,oBAAD,CAJR,EAMpB,CAACG,CAAW,EAAU,OAAAC,KAAK,CAACD,CAAD,CAAa,EAAGE,OAAO,CAACC,qBAAsB,CAAE,MAAO,CAAEH,CAAlC,E,GAElDjC,CAAC,CAAC,6BAAD,CAA+BS,IAAI,CAAC,KAAD,CAAO,CAC3CT,CAAC,CAAC,qBAAD,CAAuBS,IAAI,CAACoB,CAAD,CAAW,CACvC7B,CAAC,CAAC,qBAAD,CAAuBS,IAAI,CAACsB,CAAD,CAAQ,CACpC/B,CAAC,CAAC,gBAAD,CAAkBS,IAAI,CAACuB,CAAD,CAAO,CAE9BJ,CAAUJ,QAAQ,CAAC,YAAD,CAAca,OAAO,CAAA,EAAE,CAG7CV,CAACW,eAAe,CAAA,CAjBuD,CAAhD,CADQ,CAVtC,CAgCDrC,CAAoB,CAAA,CAAE,CACtBkB,CAA2B,CAAA,CAAE,CAC7BO,CAAqB,CAAA,CA7DZ,CAAZ,CA8DC",
"sources":["features.admin.js"],
"names":["$","initializeFeaturesUI","bulkActions","addClass","theSwitch","prepend","focus","keyup","text","val","toHide","show","each","elt","value","find","toLowerCase","indexOf","hide","initializeSelectionBehavior","on","checked","is","wrapper","parents","toggleClass","initializeActionLinks","e","actionLink","featureId","data","action","force","submit","preventDefault"]
"names":["$","initializeFeaturesUI","bulkActions","addClass","theSwitch","prepend","focus","keyup","text","val","toHide","show","each","elt","value","find","toLowerCase","indexOf","hide","initializeSelectionBehavior","on","checked","is","wrapper","parents","toggleClass","initializeActionLinks","e","actionLink","featureId","data","action","force","dependants","test","confirm","confirmDisableMessage","submit","preventDefault"]
}

View File

@@ -42,5 +42,12 @@ namespace Orchard.Modules.Services {
/// <param name="extensionDescriptor">The extension descriptor.</param>
/// <returns>True if the feature was recently installed; false otherwise.</returns>
bool IsRecentlyInstalled(ExtensionDescriptor extensionDescriptor);
/// <summary>
/// Gets a list of dependent features of a given feature.
/// </summary>
/// <param name="featureId">ID of a feature.</param>
/// <returns>List of dependent feature descriptors.</returns>
IEnumerable<FeatureDescriptor> GetDependentFeatures(string featureId);
}
}

View File

@@ -115,6 +115,15 @@ namespace Orchard.Modules.Services {
return DateTime.UtcNow.Subtract(lastWrittenUtc) < new TimeSpan(1, 0, 0, 0);
}
public IEnumerable<FeatureDescriptor> GetDependentFeatures(string featureId) {
var dependants = _featureManager.GetDependentFeatures(featureId);
var availableFeatures = _featureManager.GetAvailableFeatures().ToLookup(f => f.Id, StringComparer.OrdinalIgnoreCase);
return dependants
.SelectMany(id => availableFeatures[id])
.ToList();
}
/// <summary>
/// Retrieves the full path of the manifest file for a module's extension descriptor.
/// </summary>

View File

@@ -75,6 +75,7 @@
.Where(d => !Model.Features.Any(f => f.Descriptor.Id.Equals(d, StringComparison.OrdinalIgnoreCase)));
var showDisable = categoryName.ToString() != "Core";
var showEnable = !missingDependencies.Any() && feature.Descriptor.Id != "Orchard.Setup";
<li class="@featureClassName" id="@featureId" title="@T("{0} is {1}", Html.AttributeEncode(featureName), featureState)">
<div class="summary">
<div class="properties">
@@ -107,7 +108,8 @@
</div>
<div class="actions">
@if (showDisable && feature.IsEnabled) {
<a href="#" data-feature-id="@feature.Descriptor.Id" data-feature-action="@FeaturesBulkAction.Disable" data-feature-force="true">@T("Disable")</a>
var dependantsJoined = string.Join(", ", feature.DependentFeatures.Select(f => f.Name));
<a href="#" data-feature-id="@feature.Descriptor.Id" data-feature-action="@FeaturesBulkAction.Disable" data-feature-force="true" data-feature-dependants="@dependantsJoined">@T("Disable")</a>
}
@if (showEnable && !feature.IsEnabled) {
@@ -123,4 +125,12 @@
}</ul>
</li>}
}</ul>}
using (Script.Foot()) {
<script type="text/javascript">
//<![CDATA[
var confirmDisableMessage = '@T("Disabling this feature will also disable the following dependent features. Are you sure you want to continue?")';
//]]>
</script>
}
}