Adding recently installed indication.

--HG--
branch : dev
This commit is contained in:
Andre Rodrigues
2011-02-17 09:17:49 -08:00
parent 508ebed3fd
commit 788a9fed77
21 changed files with 251 additions and 78 deletions

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.Data.Migration; using Orchard.Data.Migration;
@@ -52,12 +53,15 @@ namespace Orchard.Modules.Controllers {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to manage modules"))) if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to manage modules")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var modules = _extensionManager.AvailableExtensions().Where(x => DefaultExtensionTypes.IsModule(x.ExtensionType)); IEnumerable<Module> modules = _extensionManager.AvailableExtensions()
.Where(x => DefaultExtensionTypes.IsModule(x.ExtensionType))
.Select(extensionDescriptor => new Module(extensionDescriptor) {
IsRecentlyInstalled = _moduleService.UpdateIsRecentlyInstalled(extensionDescriptor)
});
return View(new ModulesIndexViewModel { return View(new ModulesIndexViewModel {
Modules = modules, Modules = modules,
InstallModules = _featureManager.GetEnabledFeatures().FirstOrDefault(f => f.Id == "PackagingServices") != null, InstallModules = _featureManager.GetEnabledFeatures().FirstOrDefault(f => f.Id == "PackagingServices") != null
BrowseToGallery = _featureManager.GetEnabledFeatures().FirstOrDefault(f => f.Id == "Gallery") != null
}); });
} }
@@ -67,12 +71,14 @@ namespace Orchard.Modules.Controllers {
var featuresThatNeedUpdate = _dataMigrationManager.GetFeaturesThatNeedUpdate(); var featuresThatNeedUpdate = _dataMigrationManager.GetFeaturesThatNeedUpdate();
var features = _featureManager.GetAvailableFeatures() IEnumerable<ModuleFeature> features = _featureManager.GetAvailableFeatures()
.Where(f => !DefaultExtensionTypes.IsTheme(f.Extension.ExtensionType)) .Where(f => !DefaultExtensionTypes.IsTheme(f.Extension.ExtensionType))
.Select(f=>new ModuleFeature{Descriptor=f, .Select(f => new ModuleFeature {
IsEnabled=_shellDescriptor.Features.Any(sf=>sf.Name==f.Id), Descriptor = f,
NeedsUpdate=featuresThatNeedUpdate.Contains(f.Id)}) IsEnabled = _shellDescriptor.Features.Any(sf => sf.Name == f.Id),
.ToList(); IsRecentlyInstalled = _moduleService.UpdateIsRecentlyInstalled(f.Extension),
NeedsUpdate = featuresThatNeedUpdate.Contains(f.Id)
});
return View(new FeaturesViewModel { Features = features }); return View(new FeaturesViewModel { Features = features });
} }

View File

@@ -57,6 +57,8 @@
<Compile Include="Controllers\AdminController.cs" /> <Compile Include="Controllers\AdminController.cs" />
<Compile Include="Extensions\StringExtensions.cs" /> <Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Models\DoghouseComparer.cs" /> <Compile Include="Models\DoghouseComparer.cs" />
<Compile Include="Services\IModuleService.cs" />
<Compile Include="ViewModels\Module.cs" />
<Compile Include="ViewModels\ModuleFeature.cs" /> <Compile Include="ViewModels\ModuleFeature.cs" />
<Compile Include="ViewModels\FeaturesViewModel.cs" /> <Compile Include="ViewModels\FeaturesViewModel.cs" />
<Compile Include="Permissions.cs" /> <Compile Include="Permissions.cs" />

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Modules.Services {
public interface IModuleService : IDependency {
void EnableFeatures(IEnumerable<string> featureNames);
void EnableFeatures(IEnumerable<string> featureNames, bool force);
void DisableFeatures(IEnumerable<string> featureNames);
void DisableFeatures(IEnumerable<string> featureNames, bool force);
bool UpdateIsRecentlyInstalled(ExtensionDescriptor module);
}
}

View File

@@ -5,44 +5,35 @@ using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Environment.Descriptor; using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Descriptor.Models;
using Orchard.FileSystems.VirtualPath;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Modules.ViewModels; using Orchard.Modules.ViewModels;
using Orchard.UI.Notify; using Orchard.UI.Notify;
namespace Orchard.Modules.Services { namespace Orchard.Modules.Services {
public interface IModuleService : IDependency {
void EnableFeatures(IEnumerable<string> featureNames);
void EnableFeatures(IEnumerable<string> featureNames, bool force);
void DisableFeatures(IEnumerable<string> featureNames);
void DisableFeatures(IEnumerable<string> featureNames, bool force);
}
public class ModuleService : IModuleService { public class ModuleService : IModuleService {
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IExtensionManager _extensionManager; private readonly IExtensionManager _extensionManager;
private readonly IShellDescriptorManager _shellDescriptorManager; private readonly IShellDescriptorManager _shellDescriptorManager;
public ModuleService( public ModuleService(
IOrchardServices orchardServices, IOrchardServices orchardServices,
IVirtualPathProvider virtualPathProvider,
IExtensionManager extensionManager, IExtensionManager extensionManager,
IShellDescriptorManager shellDescriptorManager) { IShellDescriptorManager shellDescriptorManager) {
Services = orchardServices; Services = orchardServices;
_virtualPathProvider = virtualPathProvider;
_extensionManager = extensionManager; _extensionManager = extensionManager;
_shellDescriptorManager = shellDescriptorManager; _shellDescriptorManager = shellDescriptorManager;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
public Localizer T { get; set; } public Localizer T { get; set; }
public IOrchardServices Services { get; set; } public IOrchardServices Services { get; set; }
//public IModule GetModuleByName(string moduleName) {
// return _extensionManager
// .AvailableExtensions()
// .Where(e => string.Equals(e.Name, moduleName, StringComparison.OrdinalIgnoreCase))
// .Where(e => string.Equals(e.ExtensionType, ModuleExtensionType, StringComparison.OrdinalIgnoreCase))
// .Select(descriptor => AssembleModuleFromDescriptor(descriptor))
// .FirstOrDefault();
//}
public IEnumerable<ModuleFeature> GetAvailableFeatures() { public IEnumerable<ModuleFeature> GetAvailableFeatures() {
var enabledFeatures = _shellDescriptorManager.GetShellDescriptor().Features; var enabledFeatures = _shellDescriptorManager.GetShellDescriptor().Features;
return _extensionManager.AvailableExtensions() return _extensionManager.AvailableExtensions()
@@ -103,6 +94,31 @@ namespace Orchard.Modules.Services {
shellDescriptor.Parameters); shellDescriptor.Parameters);
} }
/// <summary>
/// Updates the recently installed flag by using the project's last written time.
/// </summary>
/// <param name="descriptor">The extension descriptor.</param>
public bool UpdateIsRecentlyInstalled(ExtensionDescriptor descriptor) {
string projectFile = GetManifestPath(descriptor);
if (!string.IsNullOrEmpty(projectFile)) {
// If project file was modified less than 24 hours ago, the module was recently deployed
return DateTime.UtcNow.Subtract(_virtualPathProvider.GetFileLastWriteTimeUtc(projectFile)) < new TimeSpan(1, 0, 0, 0);
}
return false;
}
private string GetManifestPath(ExtensionDescriptor descriptor) {
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id,
"module.txt");
if (!_virtualPathProvider.FileExists(projectPath)) {
return null;
}
return projectPath;
}
private IEnumerable<string> EnableFeature(string featureName, IEnumerable<ModuleFeature> features, bool force) { private IEnumerable<string> EnableFeature(string featureName, IEnumerable<ModuleFeature> features, bool force) {
var featuresList = features.ToList(); var featuresList = features.ToList();
var getDisabledDependencies = var getDisabledDependencies =

View File

@@ -4,5 +4,4 @@ namespace Orchard.Modules.ViewModels {
public class FeaturesViewModel { public class FeaturesViewModel {
public IEnumerable<ModuleFeature> Features { get; set; } public IEnumerable<ModuleFeature> Features { get; set; }
} }
} }

View File

@@ -0,0 +1,36 @@
using Orchard.Environment.Extensions.Models;
namespace Orchard.Modules.ViewModels {
/// <summary>
/// Represents a module.
/// </summary>
public class Module {
/// <summary>
/// Default constructor.
/// </summary>
public Module() {}
/// <summary>
/// Instantiates a module based on an extension descriptor.
/// </summary>
/// <param name="extensionDescriptor">The extension descriptor.</param>
public Module(ExtensionDescriptor extensionDescriptor) {
Descriptor = extensionDescriptor;
}
/// <summary>
/// The module's extension descriptor.
/// </summary>
public ExtensionDescriptor Descriptor { get; set; }
/// <summary>
/// Boolean value indicating if the module needs a version update.
/// </summary>
public bool NeedsVersionUpdate { get; set; }
/// <summary>
/// Boolean value indicating if the feature was recently installed.
/// </summary>
public bool IsRecentlyInstalled { get; set; }
}
}

View File

@@ -1,9 +1,33 @@
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
namespace Orchard.Modules.ViewModels { namespace Orchard.Modules.ViewModels {
/// <summary>
/// Represents a module's feature.
/// </summary>
public class ModuleFeature { public class ModuleFeature {
/// <summary>
/// The feature descriptor.
/// </summary>
public FeatureDescriptor Descriptor { get; set; } public FeatureDescriptor Descriptor { get; set; }
/// <summary>
/// Boolean value indicating if the feature is enabled.
/// </summary>
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
/// <summary>
/// Boolean value indicating if the feature needs a data update / migration.
/// </summary>
public bool NeedsUpdate { get; set; } public bool NeedsUpdate { get; set; }
/// <summary>
/// Boolean value indicating if the module needs a version update.
/// </summary>
public bool NeedsVersionUpdate { get; set; }
/// <summary>
/// Boolean value indicating if the feature was recently installed.
/// </summary>
public bool IsRecentlyInstalled { get; set; }
} }
} }

View File

@@ -1,11 +1,8 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Modules.ViewModels { namespace Orchard.Modules.ViewModels {
public class ModulesIndexViewModel { public class ModulesIndexViewModel {
public bool InstallModules { get; set; } public bool InstallModules { get; set; }
public bool BrowseToGallery { get; set; } public IEnumerable<Module> Modules { get; set; }
public IEnumerable<ExtensionDescriptor> Modules { get; set; }
} }
} }

View File

@@ -43,6 +43,11 @@
if (feature == features.Last()) { if (feature == features.Last()) {
featureClassName += " last"; featureClassName += " last";
} }
if (feature.IsRecentlyInstalled) {
featureClassName += " recentlyInstalledFeature";
}
var dependencies = (from d in feature.Descriptor.Dependencies var dependencies = (from d in feature.Descriptor.Dependencies
select (from f in Model.Features where f.Descriptor.Id == d select f).SingleOrDefault()).Where(f => f != null).OrderBy(f => f.Descriptor.Name); select (from f in Model.Features where f.Descriptor.Id == d select f).SingleOrDefault()).Where(f => f != null).OrderBy(f => f.Descriptor.Name);
var missingDependencies = feature.Descriptor.Dependencies var missingDependencies = feature.Descriptor.Dependencies

View File

@@ -14,23 +14,27 @@
} }
@if (Model.Modules.Count() > 0) { @if (Model.Modules.Count() > 0) {
<ul class="contentItems"> <ul class="contentItems">
@foreach (var module in Model.Modules.OrderBy(m => m.Name)) { @foreach (var module in Model.Modules.OrderBy(m => m.Descriptor.Name)) {
<li> string moduleClasses = module.IsRecentlyInstalled ? "recentlyInstalledModule" : string.Empty;
<div class="summary">
<div class="properties"> <li class="@moduleClasses">
<h2>@module.Name<span> - @T("Version: {0}", !string.IsNullOrEmpty(module.Version) ? module.Version : T("1.0").ToString())</span></h2> <div class="summary">
@if (!string.IsNullOrEmpty(module.Description)) { <div class="properties">
<p>@module.Description</p>} <h2>@module.Descriptor.Name<span> - @T("Version: {0}", !string.IsNullOrEmpty(module.Descriptor.Version) ? module.Descriptor.Version : T("1.0").ToString())</span></h2>
<ul class="pageStatus" style="color:#666; margin:.6em 0 0 0;"> @if (!string.IsNullOrEmpty(module.Descriptor.Description)) {
<li>@T("Features: {0}", MvcHtmlString.Create(string.Join(", ", module.Features.Select(f => Html.Link(string.IsNullOrEmpty(f.Name) ? f.Id : f.Name, string.Format("{0}#{1}", Url.Action("features", new { area = "Orchard.Modules" }), f.Id.AsFeatureId(n => T(n)))).ToString()).OrderBy(s => s).ToArray())))</li> <p>@module.Descriptor.Description</p>}
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(module.Author) ? module.Author : T("Unknown").ToString())</li> <ul class="pageStatus" style="color:#666; margin:.6em 0 0 0;">
<li>&nbsp;&#124;&nbsp;@T("Website: ") <li>@T("Features: {0}", MvcHtmlString.Create(string.Join(", ", module.Descriptor.Features.Select(f => Html.Link(string.IsNullOrEmpty(f.Name) ? f.Id : f.Name, string.Format("{0}#{1}", Url.Action("features", new { area = "Orchard.Modules" }), f.Id.AsFeatureId(n => T(n)))).ToString()).OrderBy(s => s).ToArray())))</li>
@if (!string.IsNullOrEmpty(module.WebSite)) { <a href="@module.WebSite">@module.WebSite</a> } <li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(module.Descriptor.Author) ? module.Descriptor.Author : T("Unknown").ToString())</li>
else { @T("Unknown").ToString() } <li>&nbsp;&#124;&nbsp;@T("Website: ")
</li> @if (!string.IsNullOrEmpty(module.Descriptor.WebSite)) { <a href="@module.Descriptor.WebSite">@module.Descriptor.WebSite</a> }
</ul> else { @T("Unknown").ToString() }
</div> </li>
</div> </ul>
</li>} </div>
</ul>} </div>
</li>
}
</ul>
}

View File

@@ -136,4 +136,13 @@
.features .feature .actions form.inline.link, .features .feature .actions form.inline.link,
.features .feature .actions a { .features .feature .actions a {
margin-left:.5em; margin-left:.5em;
}
.recentlyInstalledFeature {
background-color: Green;
}
.recentlyInstalledModule {
background-color: Green;
}
.updateAvailable {
background-color: Lime;
} }

View File

@@ -47,15 +47,11 @@
width: 171px; width: 171px;
height: 128px; height: 128px;
} }
.ratings { .ratings {
background:url(../Content/Images/stars.png) repeat-x; background:url(../Content/Images/stars.png) repeat-x;
position: relative;
height: 14px; height: 14px;
width: 75px; width: 75px;
display: block; display: block;
float: left;
clear: both;
} }
.score { .score {
background: url(../Content/Images/stars.png) repeat-x 0 -14px; background: url(../Content/Images/stars.png) repeat-x 0 -14px;

View File

@@ -65,10 +65,6 @@
} }
</div> </div>
<div class="ratings" style="width:@(15*5)px" title="@T("Ratings: {0} ({1})", item.Rating, item.RatingsCount)">
<div class="score" style="width:@(15*(item.Rating))px">&nbsp;</div>
</div>
<div class="related"> <div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary { { "packageId", item.PackageId }, { "version", item.Version }, { "sourceId", item.Source.Id }, { "redirectTo", "Modules" } })@T(" | ") @Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary { { "packageId", item.PackageId }, { "version", item.Version }, { "sourceId", item.Source.Id }, { "redirectTo", "Modules" } })@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a> <a href="@item.PackageStreamUri">@T("Download")</a>
@@ -83,6 +79,11 @@
<li>&nbsp;&#124;&nbsp;@T("Website: ") <li>&nbsp;&#124;&nbsp;@T("Website: ")
@if (!string.IsNullOrEmpty(item.ProjectUrl)) { <a href="@item.ProjectUrl">@item.ProjectUrl</a> } else { @T("Unknown").ToString() } @if (!string.IsNullOrEmpty(item.ProjectUrl)) { <a href="@item.ProjectUrl">@item.ProjectUrl</a> } else { @T("Unknown").ToString() }
</li> </li>
<li>&nbsp;&#124;&nbsp;@T("Rating")
<div class="ratings" style="width:@(15*5)px" title="@T("Ratings: {0} ({1})", item.Rating, item.RatingsCount)">
<div class="score" style="width:@(15*(item.Rating))px">&nbsp;</div>
</div>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -71,10 +71,6 @@
} }
</div> </div>
<div class="ratings" style="width:@(15*5)px" title="@T("Ratings: {0} ({1})", item.Rating, item.RatingsCount)">
<div class="score" style="width:@(15*(item.Rating))px">&nbsp;</div>
</div>
<div class="related"> <div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"packageId", item.PackageId}, {"version", item.Version}, {"sourceId", item.Source.Id}, {"redirectTo", "Themes"}})@T(" | ") @Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"packageId", item.PackageId}, {"version", item.Version}, {"sourceId", item.Source.Id}, {"redirectTo", "Themes"}})@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a> <a href="@item.PackageStreamUri">@T("Download")</a>
@@ -90,6 +86,11 @@
@if(!string.IsNullOrEmpty(item.ProjectUrl)) { <a href="@item.ProjectUrl">@item.ProjectUrl</a> } @if(!string.IsNullOrEmpty(item.ProjectUrl)) { <a href="@item.ProjectUrl">@item.ProjectUrl</a> }
else { @T("Unknown").ToString() } else { @T("Unknown").ToString() }
</li> </li>
<li>&nbsp;&#124;&nbsp;@T("Rating")
<div class="ratings" style="width:@(15*5)px" title="@T("Ratings: {0} ({1})", item.Rating, item.RatingsCount)">
<div class="score" style="width:@(15*(item.Rating))px">&nbsp;</div>
</div>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -80,6 +80,7 @@ namespace Orchard.Themes.Controllers {
}) })
.Select(extensionDescriptor => new ThemeEntry(extensionDescriptor) { .Select(extensionDescriptor => new ThemeEntry(extensionDescriptor) {
NeedsUpdate = featuresThatNeedUpdate.Contains(extensionDescriptor.Id), NeedsUpdate = featuresThatNeedUpdate.Contains(extensionDescriptor.Id),
IsRecentlyInstalled = _themeService.UpdateIsRecentlyInstalled(extensionDescriptor),
Enabled = _shellDescriptor.Features.Any(sf => sf.Name == extensionDescriptor.Id) Enabled = _shellDescriptor.Features.Any(sf => sf.Name == extensionDescriptor.Id)
}) })
.ToArray(); .ToArray();

View File

@@ -1,19 +1,51 @@
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
namespace Orchard.Themes.Models { namespace Orchard.Themes.Models {
public class ThemeEntry { /// <summary>
/// Represents a theme.
/// </summary>
public class ThemeEntry {
/// <summary>
/// Default constructor.
/// </summary>
public ThemeEntry() {} public ThemeEntry() {}
/// <summary>
/// Instantiates a theme based on an extension descriptor.
/// </summary>
/// <param name="extensionDescriptor">The extension descriptor.</param>
public ThemeEntry(ExtensionDescriptor extensionDescriptor) { public ThemeEntry(ExtensionDescriptor extensionDescriptor) {
Descriptor = extensionDescriptor; Descriptor = extensionDescriptor;
} }
/// <summary>
/// The theme's extension descriptor.
/// </summary>
public ExtensionDescriptor Descriptor { get; set; } public ExtensionDescriptor Descriptor { get; set; }
/// <summary>
/// Boolean value indicating wether the theme is enabled.
/// </summary>
public bool Enabled { get; set; } public bool Enabled { get; set; }
/// <summary>
/// Boolean value indicating wether the theme needs a data update / migration.
/// </summary>
public bool NeedsUpdate { get; set; } public bool NeedsUpdate { get; set; }
/// <summary>
/// Boolean value indicating if the module needs a version update.
/// </summary>
public bool NeedsVersionUpdate { get; set; }
/// <summary>
/// Boolean value indicating if the feature was recently installed.
/// </summary>
public bool IsRecentlyInstalled { get; set; }
/// <summary>
/// The theme's name.
/// </summary>
public string Name { get { return Descriptor.Name; } } public string Name { get { return Descriptor.Name; } }
} }
} }

View File

@@ -62,6 +62,7 @@
<Compile Include="Preview\PreviewThemeFilter.cs" /> <Compile Include="Preview\PreviewThemeFilter.cs" />
<Compile Include="Preview\PreviewThemeSelector.cs" /> <Compile Include="Preview\PreviewThemeSelector.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\IThemeService.cs" />
<Compile Include="Services\SafeModeThemeSelector.cs" /> <Compile Include="Services\SafeModeThemeSelector.cs" />
<Compile Include="Services\SiteThemeSelector.cs" /> <Compile Include="Services\SiteThemeSelector.cs" />
<Compile Include="Services\SiteThemeService.cs" /> <Compile Include="Services\SiteThemeService.cs" />

View File

@@ -0,0 +1,9 @@
using Orchard.Environment.Extensions.Models;
namespace Orchard.Themes.Services {
public interface IThemeService : IDependency {
void DisableThemeFeatures(string themeName);
void EnableThemeFeatures(string themeName);
bool UpdateIsRecentlyInstalled(ExtensionDescriptor module);
}
}

View File

@@ -3,38 +3,30 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web.Routing; using System.Web.Routing;
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Environment.Features; using Orchard.Environment.Features;
using Orchard.FileSystems.VirtualPath;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
namespace Orchard.Themes.Services { namespace Orchard.Themes.Services {
public interface IThemeService : IDependency {
void DisableThemeFeatures(string themeName);
void EnableThemeFeatures(string themeName);
}
[UsedImplicitly] [UsedImplicitly]
public class ThemeService : IThemeService { public class ThemeService : IThemeService {
private readonly IExtensionManager _extensionManager; private readonly IExtensionManager _extensionManager;
private readonly IFeatureManager _featureManager; private readonly IFeatureManager _featureManager;
private readonly IEnumerable<IThemeSelector> _themeSelectors; private readonly IEnumerable<IThemeSelector> _themeSelectors;
private readonly IVirtualPathProvider _virtualPathProvider;
public ThemeService( public ThemeService(
IShellDescriptorManager shellDescriptorManager,
IExtensionManager extensionManager, IExtensionManager extensionManager,
IFeatureManager featureManager, IFeatureManager featureManager,
IEnumerable<IThemeSelector> themeSelectors, IEnumerable<IThemeSelector> themeSelectors,
IVirtualPathProvider virtualPathProvider) {
IWorkContextAccessor workContextAccessor,
ShellDescriptor shellDescriptor,
IOrchardServices orchardServices) {
_extensionManager = extensionManager; _extensionManager = extensionManager;
_featureManager = featureManager; _featureManager = featureManager;
_themeSelectors = themeSelectors; _themeSelectors = themeSelectors;
_virtualPathProvider = virtualPathProvider;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
@@ -120,5 +112,30 @@ namespace Orchard.Themes.Services {
} }
return themes; return themes;
} }
/// <summary>
/// Updates the recently installed flag by using the project's last written time.
/// </summary>
/// <param name="descriptor">The extension descriptor.</param>
public bool UpdateIsRecentlyInstalled(ExtensionDescriptor descriptor) {
string projectFile = GetManifestPath(descriptor);
if (!string.IsNullOrEmpty(projectFile)) {
// If project file was modified less than 24 hours ago, the module was recently deployed
return DateTime.UtcNow.Subtract(_virtualPathProvider.GetFileLastWriteTimeUtc(projectFile)) < new TimeSpan(1, 0, 0, 0);
}
return false;
}
private string GetManifestPath(ExtensionDescriptor descriptor) {
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id,
"theme.txt");
if (!_virtualPathProvider.FileExists(projectPath)) {
return null;
}
return projectPath;
}
} }
} }

View File

@@ -51,3 +51,6 @@
.themePreviewImage { .themePreviewImage {
height:300px; height:300px;
} }
.recentlyInstalledTheme {
background-color: Gray;
}

View File

@@ -44,7 +44,9 @@
} else { } else {
<ul class="templates"> <ul class="templates">
@foreach (ThemeEntry theme in Model.Themes) { @foreach (ThemeEntry theme in Model.Themes) {
<li> string themeClasses = theme.IsRecentlyInstalled ? "recentlyInstalledTheme" : string.Empty;
<li class="@themeClasses">
<div> <div>
<h3>@theme.Name</h3> <h3>@theme.Name</h3>
@Html.Image(Href(Html.ThemePath(Model.CurrentTheme.Descriptor, "/Theme.png")), Html.Encode(Model.CurrentTheme.Name), null) @Html.Image(Href(Html.ThemePath(Model.CurrentTheme.Descriptor, "/Theme.png")), Html.Encode(Model.CurrentTheme.Name), null)