From 25718dbe5ac492d8eda634ac480b7387a299ed1b Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 24 Oct 2018 12:05:25 +0200 Subject: [PATCH 01/35] Add content app badges --- .../less/components/umb-editor-navigation.less | 18 +++++++++++++++++- .../editor/umb-editor-navigation.html | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index 407cfaf6a7..c58162bb5d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -19,6 +19,7 @@ align-items: center; justify-content: center; height: @editorHeaderHeight; + position: relative; } .umb-sub-views-nav-item:focus { @@ -46,6 +47,21 @@ margin-bottom: 5px; } +.umb-sub-views-nav-item .badge { + position: absolute; + top: 6px; + right: 6px; + min-width: 16px; + background-color: @turquoise-d1; + border-radius: 50%; + color: @white; + text-align: center; + font-size: 10px; + font-weight: bold; + padding: 2px; + line-height: 16px; +} + .umb-sub-views-nav-item-text { font-size: 12px; line-height: 1em; @@ -80,4 +96,4 @@ grid-template-columns: 1fr 1fr 1fr; min-width: auto; margin-top: 10px; -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index ee46a89490..f6ce09515e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -12,6 +12,7 @@ ng-class="{'is-active': item.active, '-has-error': item.hasError}"> {{ item.name }} +
{{item.badge.count}}
From 634c2072ca24fb25a790612fc826c377be0bd44f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 24 Oct 2018 15:49:35 +0200 Subject: [PATCH 02/35] Add optional alert color --- .../src/less/components/umb-editor-navigation.less | 4 ++++ .../src/views/components/editor/umb-editor-navigation.html | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index c58162bb5d..f94a874892 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -60,6 +60,10 @@ font-weight: bold; padding: 2px; line-height: 16px; + + &.-alert { + background-color: @red-l1; + } } .umb-sub-views-nav-item-text { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index f6ce09515e..c7dfa26b3c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -12,7 +12,7 @@ ng-class="{'is-active': item.active, '-has-error': item.hasError}"> {{ item.name }} -
{{item.badge.count}}
+
{{item.badge.count}}
From abcdfc27c56e2df30643764b00bfa79d9f05659f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 24 Oct 2018 20:15:17 +0200 Subject: [PATCH 03/35] Add a white border around the badge to make it stand out if it overlaps the app icon --- .../src/less/components/umb-editor-navigation.less | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index f94a874892..cb2d0c8be4 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -52,10 +52,10 @@ top: 6px; right: 6px; min-width: 16px; - background-color: @turquoise-d1; - border-radius: 50%; color: @white; - text-align: center; + background-color: @turquoise-d1; + border: 2px solid @white; + border-radius: 50%; font-size: 10px; font-weight: bold; padding: 2px; From 04d6704766a024ea95792b41cbb639b0c53bd2ec Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 8 Nov 2018 14:56:43 +0100 Subject: [PATCH 04/35] Change badge color from boolean (alert=true/false) to string (type=warning/error) --- .../src/less/components/umb-editor-navigation.less | 5 ++++- .../src/views/components/editor/umb-editor-navigation.html | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index 1a8a773c91..61cab3b477 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -61,9 +61,12 @@ padding: 2px; line-height: 16px; - &.-alert { + &.-type-alert { background-color: @red-l1; } + &.-type-warning { + background-color: @yellow-d2; + } } .umb-sub-views-nav-item-text { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index c7dfa26b3c..1f973ea2f6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -12,7 +12,7 @@ ng-class="{'is-active': item.active, '-has-error': item.hasError}"> {{ item.name }} -
{{item.badge.count}}
+
{{item.badge.count}}
From b861b379db64a5cce7d4be957ac962db31c5145d Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sat, 5 Jan 2019 18:47:23 +0100 Subject: [PATCH 05/35] Make the on-click-outside directive work again --- .../src/common/directives/components/events/events.directive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js index 7578ade867..6e75973ae7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js @@ -136,7 +136,7 @@ angular.module('umbraco.directives') return; } - angularHelper.safeApply(scope, attrs.onOutsideClick); + scope.$apply(attrs.onOutsideClick); } From 5855eaa4c969f2e0127e6d0b2ae750f4d317206c Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 7 Jan 2019 09:31:51 +0100 Subject: [PATCH 06/35] Fix nuspec --- build/NuSpecs/UmbracoCms.nuspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index fbe990f2de..55703d1509 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -25,8 +25,8 @@ - - + + From 84f6239c982b1eba5b1d095fdf365d2d027446bf Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 7 Jan 2019 09:30:47 +0100 Subject: [PATCH 07/35] Components Initialize and Terminate --- .../Components/AuditEventsComponent.cs | 6 ++ .../Components/ComponentCollection.cs | 16 ++++ src/Umbraco.Core/Components/IComponent.cs | 16 +++- .../Components/ManifestWatcherComponent.cs | 20 +++-- .../Components/RelateOnCopyComponent.cs | 5 +- .../Components/RelateOnTrashComponent.cs | 5 +- src/Umbraco.Core/Runtime/CoreRuntime.cs | 3 +- .../Runtime/CoreRuntimeComponent.cs | 12 ++- .../Components/ComponentTests.cs | 75 +++++++++++++++---- .../Runtimes/CoreRuntimeTests.cs | 16 +++- .../Cache/DistributedCacheBinderComponent.cs | 12 ++- .../BackOfficeUserAuditEventsComponent.cs | 18 +++-- ...aseServerRegistrarAndMessengerComponent.cs | 6 ++ .../Components/NotificationsComponent.cs | 26 +++++-- .../Components/PublicAccessComponent.cs | 5 +- .../Logging/WebProfilerComponent.cs | 31 +++++--- .../PropertyEditorsComponent.cs | 15 +++- .../NuCache/NuCacheComponent.cs | 6 ++ .../Routing/RedirectTrackingComponent.cs | 6 +- .../Runtime/WebRuntimeComponent.cs | 46 +++++++++--- .../Scheduling/SchedulerComponent.cs | 28 ++++--- src/Umbraco.Web/Search/ExamineComponent.cs | 39 ++++++---- .../SignalR/PreviewHubComponent.cs | 47 +++++++----- 23 files changed, 340 insertions(+), 119 deletions(-) diff --git a/src/Umbraco.Core/Components/AuditEventsComponent.cs b/src/Umbraco.Core/Components/AuditEventsComponent.cs index f592613e0d..08d4702afa 100644 --- a/src/Umbraco.Core/Components/AuditEventsComponent.cs +++ b/src/Umbraco.Core/Components/AuditEventsComponent.cs @@ -23,7 +23,10 @@ namespace Umbraco.Core.Components _auditService = auditService; _userService = userService; _entityService = entityService; + } + public void Initialize() + { UserService.SavedUserGroup += OnSavedUserGroupWithUsers; UserService.SavedUser += OnSavedUser; @@ -37,6 +40,9 @@ namespace Umbraco.Core.Components MemberService.Exported += OnMemberExported; } + public void Terminate() + { } + private IUser CurrentPerformingUser { get diff --git a/src/Umbraco.Core/Components/ComponentCollection.cs b/src/Umbraco.Core/Components/ComponentCollection.cs index abe493b524..4fa81b9760 100644 --- a/src/Umbraco.Core/Components/ComponentCollection.cs +++ b/src/Umbraco.Core/Components/ComponentCollection.cs @@ -20,6 +20,21 @@ namespace Umbraco.Core.Components _logger = logger; } + public void Initialize() + { + using (_logger.DebugDuration($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized.")) + { + foreach (var component in this.Reverse()) // terminate components in reverse order + { + var componentType = component.GetType(); + using (_logger.DebugDuration($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) + { + component.Initialize(); + } + } + } + } + public void Terminate() { using (_logger.DebugDuration($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated.")) @@ -29,6 +44,7 @@ namespace Umbraco.Core.Components var componentType = component.GetType(); using (_logger.DebugDuration($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { + component.Terminate(); component.DisposeIfDisposable(); } } diff --git a/src/Umbraco.Core/Components/IComponent.cs b/src/Umbraco.Core/Components/IComponent.cs index 28ca539387..b1954d821b 100644 --- a/src/Umbraco.Core/Components/IComponent.cs +++ b/src/Umbraco.Core/Components/IComponent.cs @@ -5,11 +5,21 @@ /// /// /// Components are created by DI and therefore must have a public constructor. - /// All components which are also disposable, will be disposed in reverse - /// order, when Umbraco terminates. + /// All components are terminated in reverse order when Umbraco terminates, and + /// disposable components are disposed. /// The Dispose method may be invoked more than once, and components /// should ensure they support this. /// public interface IComponent - { } + { + /// + /// Initializes the component. + /// + void Initialize(); + + /// + /// Terminates the component. + /// + void Terminate(); + } } diff --git a/src/Umbraco.Core/Components/ManifestWatcherComponent.cs b/src/Umbraco.Core/Components/ManifestWatcherComponent.cs index a96dd516e7..2420e1d5bb 100644 --- a/src/Umbraco.Core/Components/ManifestWatcherComponent.cs +++ b/src/Umbraco.Core/Components/ManifestWatcherComponent.cs @@ -1,20 +1,28 @@ -using System; -using System.IO; +using System.IO; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; namespace Umbraco.Core.Components { - public sealed class ManifestWatcherComponent : IComponent, IDisposable + public sealed class ManifestWatcherComponent : IComponent { + private readonly IRuntimeState _runtimeState; + private readonly ILogger _logger; + // if configured and in debug mode, a ManifestWatcher watches App_Plugins folders for // package.manifest chances and restarts the application on any change private ManifestWatcher _mw; public ManifestWatcherComponent(IRuntimeState runtimeState, ILogger logger) { - if (runtimeState.Debug == false) return; + _runtimeState = runtimeState; + _logger = logger; + } + + public void Initialize() + { + if (_runtimeState.Debug == false) return; //if (ApplicationContext.Current.IsConfigured == false || GlobalSettings.DebugMode == false) // return; @@ -22,11 +30,11 @@ namespace Umbraco.Core.Components var appPlugins = IOHelper.MapPath("~/App_Plugins/"); if (Directory.Exists(appPlugins) == false) return; - _mw = new ManifestWatcher(logger); + _mw = new ManifestWatcher(_logger); _mw.Start(Directory.GetDirectories(appPlugins)); } - public void Dispose() + public void Terminate() { if (_mw == null) return; diff --git a/src/Umbraco.Core/Components/RelateOnCopyComponent.cs b/src/Umbraco.Core/Components/RelateOnCopyComponent.cs index 41ae3c70dc..404d385680 100644 --- a/src/Umbraco.Core/Components/RelateOnCopyComponent.cs +++ b/src/Umbraco.Core/Components/RelateOnCopyComponent.cs @@ -8,11 +8,14 @@ namespace Umbraco.Core.Components //TODO: This should just exist in the content service/repo! public sealed class RelateOnCopyComponent : IComponent { - public RelateOnCopyComponent() + public void Initialize() { ContentService.Copied += ContentServiceCopied; } + public void Terminate() + { } + private static void ContentServiceCopied(IContentService sender, Events.CopyEventArgs e) { if (e.RelateToOriginal == false) return; diff --git a/src/Umbraco.Core/Components/RelateOnTrashComponent.cs b/src/Umbraco.Core/Components/RelateOnTrashComponent.cs index 93803d4fae..6279bb98ba 100644 --- a/src/Umbraco.Core/Components/RelateOnTrashComponent.cs +++ b/src/Umbraco.Core/Components/RelateOnTrashComponent.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Components { public sealed class RelateOnTrashComponent : IComponent { - public RelateOnTrashComponent() + public void Initialize() { ContentService.Moved += ContentService_Moved; ContentService.Trashed += ContentService_Trashed; @@ -17,6 +17,9 @@ namespace Umbraco.Core.Components MediaService.Trashed += MediaService_Trashed; } + public void Terminate() + { } + private static void ContentService_Moved(IContentService sender, MoveEventArgs e) { foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContent.ToInvariantString()))) diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 3a698dd30d..7a4314c968 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -146,8 +146,9 @@ namespace Umbraco.Core.Runtime // create the factory _factory = Current.Factory = composition.CreateFactory(); - // create the components + // create & initialize the components _components = _factory.GetInstance(); + _components.Initialize(); } catch (Exception e) { diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs index 9e61feb15d..b9efdd6432 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs @@ -7,12 +7,19 @@ namespace Umbraco.Core.Runtime { public class CoreRuntimeComponent : IComponent { + private readonly IEnumerable _mapperProfiles; + public CoreRuntimeComponent(IEnumerable mapperProfiles) + { + _mapperProfiles = mapperProfiles; + } + + public void Initialize() { // mapper profiles have been registered & are created by the container Mapper.Initialize(configuration => { - foreach (var profile in mapperProfiles) + foreach (var profile in _mapperProfiles) configuration.AddProfile(profile); }); @@ -24,5 +31,8 @@ namespace Umbraco.Core.Runtime IOHelper.EnsurePathExists(SystemDirectories.MvcViews + "/Partials"); IOHelper.EnsurePathExists(SystemDirectories.MvcViews + "/MacroPartials"); } + + public void Terminate() + { } } } diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs index 903c53292c..a04636f919 100644 --- a/src/Umbraco.Tests/Components/ComponentTests.cs +++ b/src/Umbraco.Tests/Components/ComponentTests.cs @@ -18,7 +18,8 @@ namespace Umbraco.Tests.Components public class ComponentTests { private static readonly List Composed = new List(); - private static readonly List Initialized = new List(); + private static readonly List Initialized = new List(); + private static readonly List Terminated = new List(); private static IFactory MockFactory(Action> setup = null) { @@ -64,13 +65,36 @@ namespace Umbraco.Tests.Components var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown)); var types = TypeArray(); - var components = new Core.Components.Composers(composition, types, Mock.Of()); + var composers = new Composers(composition, types, Mock.Of()); Composed.Clear(); // 2 is Core and requires 4 // 3 is User - goes away with RuntimeLevel.Unknown // => reorder components accordingly - components.Compose(); + composers.Compose(); AssertTypeArray(TypeArray(), Composed); + + var factory = MockFactory(m => + { + m.Setup(x => x.TryGetInstance(It.Is(t => t == typeof(ISomeResource)))).Returns(() => new SomeResource()); + m.Setup(x => x.GetInstance(It.IsAny())).Returns((type) => + { + if (type == typeof(Composer1)) return new Composer1(); + if (type == typeof(Composer5)) return new Composer5(); + if (type == typeof(Component5)) return new Component5(new SomeResource()); + if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of(), Mock.Of()); + throw new NotSupportedException(type.FullName); + }); + }); + + var builder = composition.WithCollectionBuilder(); + builder.RegisterWith(register); + var components = builder.CreateCollection(factory); + + Assert.IsEmpty(components); + components.Initialize(); + Assert.IsEmpty(Initialized); + components.Terminate(); + Assert.IsEmpty(Terminated); } [Test] @@ -164,6 +188,10 @@ namespace Umbraco.Tests.Components [Test] public void Initialize() { + Composed.Clear(); + Initialized.Clear(); + Terminated.Clear(); + var register = MockRegister(); var factory = MockFactory(m => { @@ -181,17 +209,22 @@ namespace Umbraco.Tests.Components var types = new[] { typeof(Composer1), typeof(Composer5) }; var composers = new Composers(composition, types, Mock.Of()); - Composed.Clear(); - Initialized.Clear(); + + Assert.IsEmpty(Composed); composers.Compose(); + AssertTypeArray(TypeArray(), Composed); + var builder = composition.WithCollectionBuilder(); builder.RegisterWith(register); var components = builder.CreateCollection(factory); - Assert.AreEqual(2, Composed.Count); - Assert.AreEqual(typeof(Composer1), Composed[0]); - Assert.AreEqual(typeof(Composer5), Composed[1]); - Assert.AreEqual(1, Initialized.Count); - Assert.AreEqual("Umbraco.Tests.Components.ComponentTests+SomeResource", Initialized[0]); + + Assert.IsEmpty(Initialized); + components.Initialize(); + AssertTypeArray(TypeArray(), Initialized); + + Assert.IsEmpty(Terminated); + components.Terminate(); + AssertTypeArray(TypeArray(), Terminated); } [Test] @@ -301,9 +334,6 @@ namespace Umbraco.Tests.Components } } - public class TestComponentBase : IComponent - { } - public class Composer1 : TestComposerBase { } @@ -326,11 +356,26 @@ namespace Umbraco.Tests.Components } } - public class Component5 : IComponent + public class TestComponentBase : IComponent { + public virtual void Initialize() + { + Initialized.Add(GetType()); + } + + public virtual void Terminate() + { + Terminated.Add(GetType()); + } + } + + public class Component5 : TestComponentBase + { + private readonly ISomeResource _resource; + public Component5(ISomeResource resource) { - Initialized.Add(resource.GetType().FullName); + _resource = resource; } } diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs index ca70ac5b6a..5be0617f52 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -191,8 +191,7 @@ namespace Umbraco.Tests.Runtimes { // test flags public static bool Ctored; - public static bool Initialized1; - public static bool Initialized2; + public static bool Initialized; public static bool Terminated; public static IProfilingLogger ProfilingLogger; @@ -200,7 +199,7 @@ namespace Umbraco.Tests.Runtimes public static void Reset() { - Ctored = Initialized1 = Initialized2 = Terminated = false; + Ctored = Initialized = Terminated = false; ProfilingLogger = null; } @@ -210,10 +209,19 @@ namespace Umbraco.Tests.Runtimes ProfilingLogger = proflog; } + public void Initialize() + { + Initialized = true; + } + + public void Terminate() + { + Terminated = true; + } + public void Dispose() { Disposed = true; - Terminated = true; } } } diff --git a/src/Umbraco.Web/Cache/DistributedCacheBinderComponent.cs b/src/Umbraco.Web/Cache/DistributedCacheBinderComponent.cs index 91646e3624..94d274731d 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheBinderComponent.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheBinderComponent.cs @@ -4,9 +4,19 @@ namespace Umbraco.Web.Cache { public class DistributedCacheBinderComponent : IComponent { + private readonly IDistributedCacheBinder _binder; + public DistributedCacheBinderComponent(IDistributedCacheBinder distributedCacheBinder) { - distributedCacheBinder.BindEvents(); + _binder = distributedCacheBinder; } + + public void Initialize() + { + _binder.BindEvents(); + } + + public void Terminate() + { } } } diff --git a/src/Umbraco.Web/Components/BackOfficeUserAuditEventsComponent.cs b/src/Umbraco.Web/Components/BackOfficeUserAuditEventsComponent.cs index 81b900fc3a..545a781a8d 100644 --- a/src/Umbraco.Web/Components/BackOfficeUserAuditEventsComponent.cs +++ b/src/Umbraco.Web/Components/BackOfficeUserAuditEventsComponent.cs @@ -12,17 +12,14 @@ namespace Umbraco.Web.Components private readonly IAuditService _auditService; private readonly IUserService _userService; - private IUser GetPerformingUser(int userId) - { - var found = userId >= 0 ? _userService.GetUserById(userId) : null; - return found ?? new User {Id = 0, Name = "SYSTEM", Email = ""}; - } - public BackOfficeUserAuditEventsComponent(IAuditService auditService, IUserService userService) { _auditService = auditService; _userService = userService; + } + public void Initialize() + { //BackOfficeUserManager.AccountLocked += ; //BackOfficeUserManager.AccountUnlocked += ; BackOfficeUserManager.ForgotPasswordRequested += OnForgotPasswordRequest; @@ -34,7 +31,15 @@ namespace Umbraco.Web.Components BackOfficeUserManager.PasswordChanged += OnPasswordChanged; BackOfficeUserManager.PasswordReset += OnPasswordReset; //BackOfficeUserManager.ResetAccessFailedCount += ; + } + public void Terminate() + { } + + private IUser GetPerformingUser(int userId) + { + var found = userId >= 0 ? _userService.GetUserById(userId) : null; + return found ?? new User { Id = 0, Name = "SYSTEM", Email = "" }; } private static string FormatEmail(IMembershipUser user) @@ -42,7 +47,6 @@ namespace Umbraco.Web.Components return user == null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? "" : $"<{user.Email}>"; } - private void OnLoginSuccess(object sender, EventArgs args) { if (args is IdentityAuditEventArgs identityArgs) diff --git a/src/Umbraco.Web/Components/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Web/Components/DatabaseServerRegistrarAndMessengerComponent.cs index bd3b50bd9a..2e3132a82c 100644 --- a/src/Umbraco.Web/Components/DatabaseServerRegistrarAndMessengerComponent.cs +++ b/src/Umbraco.Web/Components/DatabaseServerRegistrarAndMessengerComponent.cs @@ -121,7 +121,10 @@ namespace Umbraco.Web.Components new BackgroundTaskRunnerOptions { AutoStart = true }, logger); _processTaskRunner = new BackgroundTaskRunner("ServerInstProcess", new BackgroundTaskRunnerOptions { AutoStart = true }, logger); + } + public void Initialize() + { //We will start the whole process when a successful request is made UmbracoModule.RouteAttempt += RegisterBackgroundTasksOnce; @@ -129,6 +132,9 @@ namespace Umbraco.Web.Components _messenger.Startup(); } + public void Terminate() + { } + /// /// Handle when a request is made /// diff --git a/src/Umbraco.Web/Components/NotificationsComponent.cs b/src/Umbraco.Web/Components/NotificationsComponent.cs index 9314181c15..4b447598a3 100644 --- a/src/Umbraco.Web/Components/NotificationsComponent.cs +++ b/src/Umbraco.Web/Components/NotificationsComponent.cs @@ -18,27 +18,39 @@ namespace Umbraco.Web.Components { public sealed class NotificationsComponent : IComponent { - public NotificationsComponent(INotificationService notificationService, Notifier notifier, ActionCollection actions) + private readonly Notifier _notifier; + private readonly ActionCollection _actions; + + public NotificationsComponent(Notifier notifier, ActionCollection actions) + { + _notifier = notifier; + _actions = actions; + } + + public void Initialize() { //Send notifications for the send to publish action - ContentService.SentToPublish += (sender, args) => notifier.Notify(actions.GetAction(), args.Entity); + ContentService.SentToPublish += (sender, args) => _notifier.Notify(_actions.GetAction(), args.Entity); //Send notifications for the published action - ContentService.Published += (sender, args) => notifier.Notify(actions.GetAction(), args.PublishedEntities.ToArray()); + ContentService.Published += (sender, args) => _notifier.Notify(_actions.GetAction(), args.PublishedEntities.ToArray()); //Send notifications for the saved action - ContentService.Sorted += (sender, args) => ContentServiceSorted(notifier, sender, args, actions); + ContentService.Sorted += (sender, args) => ContentServiceSorted(_notifier, sender, args, _actions); //Send notifications for the update and created actions - ContentService.Saved += (sender, args) => ContentServiceSaved(notifier, sender, args, actions); + ContentService.Saved += (sender, args) => ContentServiceSaved(_notifier, sender, args, _actions); //Send notifications for the delete action - ContentService.Deleted += (sender, args) => notifier.Notify(actions.GetAction(), args.DeletedEntities.ToArray()); + ContentService.Deleted += (sender, args) => _notifier.Notify(_actions.GetAction(), args.DeletedEntities.ToArray()); //Send notifications for the unpublish action - ContentService.Unpublished += (sender, args) => notifier.Notify(actions.GetAction(), args.PublishedEntities.ToArray()); + ContentService.Unpublished += (sender, args) => _notifier.Notify(_actions.GetAction(), args.PublishedEntities.ToArray()); } + public void Terminate() + { } + private void ContentServiceSorted(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs args, ActionCollection actions) { var parentId = args.SavedEntities.Select(x => x.ParentId).Distinct().ToList(); diff --git a/src/Umbraco.Web/Components/PublicAccessComponent.cs b/src/Umbraco.Web/Components/PublicAccessComponent.cs index 09c1108295..e08d42d961 100644 --- a/src/Umbraco.Web/Components/PublicAccessComponent.cs +++ b/src/Umbraco.Web/Components/PublicAccessComponent.cs @@ -8,11 +8,14 @@ namespace Umbraco.Web.Components { public sealed class PublicAccessComponent : IComponent { - public PublicAccessComponent() + public void Initialize() { MemberGroupService.Saved += MemberGroupService_Saved; } + public void Terminate() + { } + static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs e) { foreach (var grp in e.SavedEntities) diff --git a/src/Umbraco.Web/Logging/WebProfilerComponent.cs b/src/Umbraco.Web/Logging/WebProfilerComponent.cs index 418ea66d23..b61bcd372c 100755 --- a/src/Umbraco.Web/Logging/WebProfilerComponent.cs +++ b/src/Umbraco.Web/Logging/WebProfilerComponent.cs @@ -1,6 +1,5 @@ using System; using System.Web; -using Umbraco.Core; using Umbraco.Core.Components; using Umbraco.Core.Logging; @@ -9,30 +8,38 @@ namespace Umbraco.Web.Logging internal sealed class WebProfilerComponent : IComponent { private readonly WebProfiler _profiler; + private readonly bool _profile; - public WebProfilerComponent(IProfiler profiler, ILogger logger, IRuntimeState runtime) + public WebProfilerComponent(IProfiler profiler, ILogger logger) { + _profile = true; + // although registered in WebRuntime.Compose, ensure that we have not // been replaced by another component, and we are still "the" profiler _profiler = profiler as WebProfiler; - if (_profiler == null) - { - // if VoidProfiler was registered, let it be known - var vp = profiler as VoidProfiler; - if (vp != null) - logger.Info("Profiler is VoidProfiler, not profiling (must run debug mode to profile)."); - return; - } + if (_profiler != null) return; + + // if VoidProfiler was registered, let it be known + if (profiler is VoidProfiler) + logger.Info("Profiler is VoidProfiler, not profiling (must run debug mode to profile)."); + _profile = false; + } + + public void Initialize() + { + if (!_profile) return; // bind to ApplicationInit - ie execute the application initialization for *each* application // it would be a mistake to try and bind to the current application events UmbracoApplicationBase.ApplicationInit += InitializeApplication; } + public void Terminate() + { } + private void InitializeApplication(object sender, EventArgs args) { - var app = sender as HttpApplication; - if (app == null) return; + if (!(sender is HttpApplication app)) return; // for *each* application (this will run more than once) app.BeginRequest += (s, a) => _profiler.UmbracoApplicationBeginRequest(s, a); diff --git a/src/Umbraco.Web/PropertyEditors/PropertyEditorsComponent.cs b/src/Umbraco.Web/PropertyEditors/PropertyEditorsComponent.cs index e719a72160..2fc3badb85 100644 --- a/src/Umbraco.Web/PropertyEditors/PropertyEditorsComponent.cs +++ b/src/Umbraco.Web/PropertyEditors/PropertyEditorsComponent.cs @@ -1,5 +1,4 @@ using System.Linq; -using Umbraco.Core; using Umbraco.Core.Components; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -9,18 +8,26 @@ namespace Umbraco.Web.PropertyEditors { internal sealed class PropertyEditorsComponent : IComponent { + private readonly PropertyEditorCollection _propertyEditors; + public PropertyEditorsComponent(PropertyEditorCollection propertyEditors) { - var fileUpload = propertyEditors.OfType().FirstOrDefault(); + _propertyEditors = propertyEditors; + } + + public void Initialize() + { + var fileUpload = _propertyEditors.OfType().FirstOrDefault(); if (fileUpload != null) Initialize(fileUpload); - var imageCropper = propertyEditors.OfType().FirstOrDefault(); + var imageCropper = _propertyEditors.OfType().FirstOrDefault(); if (imageCropper != null) Initialize(imageCropper); // grid/examine moved to ExamineComponent } - // as long as these methods are private+static they won't be executed by the boot loader + public void Terminate() + { } private static void Initialize(FileUploadPropertyEditor fileUpload) { diff --git a/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComponent.cs b/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComponent.cs index fcb2f016b0..089ff6a8ea 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComponent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComponent.cs @@ -8,5 +8,11 @@ namespace Umbraco.Web.PublishedCache.NuCache { // nothing - this just ensures that the service is created at boot time } + + public void Initialize() + { } + + public void Terminate() + { } } } diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs index e0af787e84..6cebf857ac 100644 --- a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs +++ b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs @@ -69,8 +69,7 @@ namespace Umbraco.Web.Redirects } } - public RedirectTrackingComponent() - //protected void Initialize(ContentFinderCollectionBuilder contentFinderCollectionBuilder) + public void Initialize() { // don't let the event handlers kick in if Redirect Tracking is turned off in the config if (UmbracoConfig.GetConfig("umbracoConfiguration/settings").WebRouting.DisableRedirectUrlTracking) return; @@ -103,6 +102,9 @@ namespace Umbraco.Web.Redirects // rolled back items have to be published, so publishing will take care of that } + public void Terminate() + { } + private static void ContentCacheRefresher_CacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) { diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 8aff0457ea..0199a34579 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -34,8 +34,17 @@ namespace Umbraco.Web.Runtime { public sealed class WebRuntimeComponent : IComponent { + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly SurfaceControllerTypeCollection _surfaceControllerTypes; + private readonly UmbracoApiControllerTypeCollection _apiControllerTypes; + private readonly IPublishedSnapshotService _publishedSnapshotService; + private readonly IUserService _userService; + private readonly IUmbracoSettingsSection _umbracoSettings; + private readonly IGlobalSettings _globalSettings; + private readonly IVariationContextAccessor _variationContextAccessor; + private readonly UrlProviderCollection _urlProviders; + public WebRuntimeComponent( - IRuntimeState runtime, IUmbracoContextAccessor umbracoContextAccessor, SurfaceControllerTypeCollection surfaceControllerTypes, UmbracoApiControllerTypeCollection apiControllerTypes, @@ -43,15 +52,27 @@ namespace Umbraco.Web.Runtime IUserService userService, IUmbracoSettingsSection umbracoSettings, IGlobalSettings globalSettings, - IEntityService entityService, IVariationContextAccessor variationContextAccessor, UrlProviderCollection urlProviders) { + _umbracoContextAccessor = umbracoContextAccessor; + _surfaceControllerTypes = surfaceControllerTypes; + _apiControllerTypes = apiControllerTypes; + _publishedSnapshotService = publishedSnapshotService; + _userService = userService; + _umbracoSettings = umbracoSettings; + _globalSettings = globalSettings; + _variationContextAccessor = variationContextAccessor; + _urlProviders = urlProviders; + } + + public void Initialize() + { // setup mvc and webapi services SetupMvcAndWebApi(); // client dependency - ConfigureClientDependency(globalSettings); + ConfigureClientDependency(_globalSettings); // Disable the X-AspNetMvc-Version HTTP Header MvcHandler.DisableMvcResponseHeader = true; @@ -65,7 +86,7 @@ namespace Umbraco.Web.Runtime ConfigureGlobalFilters(); // set routes - CreateRoutes(umbracoContextAccessor, globalSettings, surfaceControllerTypes, apiControllerTypes); + CreateRoutes(_umbracoContextAccessor, _globalSettings, _surfaceControllerTypes, _apiControllerTypes); // get an http context // at that moment, HttpContext.Current != null but its .Request property is null @@ -75,19 +96,22 @@ namespace Umbraco.Web.Runtime // (also sets the accessor) // this is a *temp* UmbracoContext UmbracoContext.EnsureContext( - umbracoContextAccessor, + _umbracoContextAccessor, new HttpContextWrapper(HttpContext.Current), - publishedSnapshotService, - new WebSecurity(httpContext, userService, globalSettings), - umbracoSettings, - urlProviders, - globalSettings, - variationContextAccessor); + _publishedSnapshotService, + new WebSecurity(httpContext, _userService, _globalSettings), + _umbracoSettings, + _urlProviders, + _globalSettings, + _variationContextAccessor); // ensure WebAPI is initialized, after everything GlobalConfiguration.Configuration.EnsureInitialized(); } + public void Terminate() + { } + private static void ConfigureGlobalFilters() { GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute()); diff --git a/src/Umbraco.Web/Scheduling/SchedulerComponent.cs b/src/Umbraco.Web/Scheduling/SchedulerComponent.cs index efd9d60fe8..acfb2b4608 100644 --- a/src/Umbraco.Web/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Web/Scheduling/SchedulerComponent.cs @@ -24,11 +24,11 @@ namespace Umbraco.Web.Scheduling private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; - private readonly BackgroundTaskRunner _keepAliveRunner; - private readonly BackgroundTaskRunner _publishingRunner; - private readonly BackgroundTaskRunner _tasksRunner; - private readonly BackgroundTaskRunner _scrubberRunner; - private readonly BackgroundTaskRunner _healthCheckRunner; + private BackgroundTaskRunner _keepAliveRunner; + private BackgroundTaskRunner _publishingRunner; + private BackgroundTaskRunner _tasksRunner; + private BackgroundTaskRunner _scrubberRunner; + private BackgroundTaskRunner _healthCheckRunner; private bool _started; private object _locker = new object(); @@ -47,18 +47,26 @@ namespace Umbraco.Web.Scheduling _healthChecks = healthChecks; _notifications = notifications; + } + public void Initialize() + { // backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly - _keepAliveRunner = new BackgroundTaskRunner("KeepAlive", logger); - _publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", logger); - _tasksRunner = new BackgroundTaskRunner("ScheduledTasks", logger); - _scrubberRunner = new BackgroundTaskRunner("LogScrubber", logger); - _healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", logger); + _keepAliveRunner = new BackgroundTaskRunner("KeepAlive", _logger); + _publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", _logger); + _tasksRunner = new BackgroundTaskRunner("ScheduledTasks", _logger); + _scrubberRunner = new BackgroundTaskRunner("LogScrubber", _logger); + _healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", _logger); // we will start the whole process when a successful request is made UmbracoModule.RouteAttempt += RegisterBackgroundTasksOnce; } + public void Terminate() + { + // the appdomain / maindom / whatever takes care of stopping background task runners + } + private void RegisterBackgroundTasksOnce(object sender, RoutableAttemptEventArgs e) { switch (e.Outcome) diff --git a/src/Umbraco.Web/Search/ExamineComponent.cs b/src/Umbraco.Web/Search/ExamineComponent.cs index 81543c6dcc..09d0c555da 100644 --- a/src/Umbraco.Web/Search/ExamineComponent.cs +++ b/src/Umbraco.Web/Search/ExamineComponent.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.Search { private readonly IExamineManager _examineManager; private readonly IContentValueSetBuilder _contentValueSetBuilder; - public IPublishedContentValueSetBuilder _publishedContentValueSetBuilder; + private readonly IPublishedContentValueSetBuilder _publishedContentValueSetBuilder; private readonly IValueSetBuilder _mediaValueSetBuilder; private readonly IValueSetBuilder _memberValueSetBuilder; private static bool _disableExamineIndexing = false; @@ -36,6 +36,10 @@ namespace Umbraco.Web.Search private readonly ServiceContext _services; private static BackgroundTaskRunner _rebuildOnStartupRunner; private static readonly object RebuildLocker = new object(); + private readonly IMainDom _mainDom; + private readonly IProfilingLogger _logger; + private readonly IUmbracoIndexesCreator _indexCreator; + private readonly IndexRebuilder _indexRebuilder; // the default enlist priority is 100 // enlist with a lower priority to ensure that anything "default" runs after us @@ -59,6 +63,14 @@ namespace Umbraco.Web.Search _mediaValueSetBuilder = mediaValueSetBuilder; _memberValueSetBuilder = memberValueSetBuilder; + _mainDom = mainDom; + _logger = profilingLogger; + _indexCreator = indexCreator; + _indexRebuilder = indexRebuilder; + } + + public void Initialize() + { //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock //which simply checks the existence of the lock file @@ -69,9 +81,9 @@ namespace Umbraco.Web.Search }; //let's deal with shutting down Examine with MainDom - var examineShutdownRegistered = mainDom.Register(() => + var examineShutdownRegistered = _mainDom.Register(() => { - using (profilingLogger.TraceDuration("Examine shutting down")) + using (_logger.TraceDuration("Examine shutting down")) { _examineManager.Dispose(); } @@ -79,23 +91,23 @@ namespace Umbraco.Web.Search if (!examineShutdownRegistered) { - profilingLogger.Debug("Examine shutdown not registered, this appdomain is not the MainDom, Examine will be disabled"); + _logger.Debug("Examine shutdown not registered, this appdomain is not the MainDom, Examine will be disabled"); //if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled! - Suspendable.ExamineEvents.SuspendIndexers(profilingLogger); + Suspendable.ExamineEvents.SuspendIndexers(_logger); _disableExamineIndexing = true; return; //exit, do not continue } //create the indexes and register them with the manager - foreach(var index in indexCreator.Create()) + foreach(var index in _indexCreator.Create()) _examineManager.AddIndex(index); - profilingLogger.Debug("Examine shutdown registered with MainDom"); + _logger.Debug("Examine shutdown registered with MainDom"); - var registeredIndexers = examineManager.Indexes.OfType().Count(x => x.EnableDefaultEventHandler); + var registeredIndexers = _examineManager.Indexes.OfType().Count(x => x.EnableDefaultEventHandler); - profilingLogger.Info("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers); + _logger.Info("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers); // don't bind event handlers if we're not suppose to listen if (registeredIndexers == 0) @@ -108,12 +120,15 @@ namespace Umbraco.Web.Search MediaCacheRefresher.CacheUpdated += MediaCacheRefresherUpdated; MemberCacheRefresher.CacheUpdated += MemberCacheRefresherUpdated; - EnsureUnlocked(profilingLogger, examineManager); + EnsureUnlocked(_logger, _examineManager); //TODO: Instead of waiting 5000 ms, we could add an event handler on to fulfilling the first request, then start? - RebuildIndexes(indexRebuilder, profilingLogger, true, 5000); + RebuildIndexes(_indexRebuilder, _logger, true, 5000); } + public void Terminate() + { } + /// /// Called to rebuild empty indexes on startup /// @@ -146,8 +161,6 @@ namespace Umbraco.Web.Search } } - - /// /// Must be called to each index is unlocked before any indexing occurs /// diff --git a/src/Umbraco.Web/SignalR/PreviewHubComponent.cs b/src/Umbraco.Web/SignalR/PreviewHubComponent.cs index 1ca8ad0176..328f5a06ed 100644 --- a/src/Umbraco.Web/SignalR/PreviewHubComponent.cs +++ b/src/Umbraco.Web/SignalR/PreviewHubComponent.cs @@ -1,5 +1,6 @@ using System; using Microsoft.AspNet.SignalR; +using Umbraco.Core.Cache; using Umbraco.Core.Components; using Umbraco.Core.Sync; using Umbraco.Web.Cache; @@ -8,31 +9,39 @@ namespace Umbraco.Web.SignalR { public class PreviewHubComponent : IComponent { + private readonly Lazy> _hubContext; + // using a lazy arg here means that we won't create the hub until necessary // and therefore we won't have too bad an impact on boot time public PreviewHubComponent(Lazy> hubContext) { - // ContentService.Saved is too soon - the content cache is not ready yet - // try using the content cache refresher event, because when it triggers - // the cache has already been notified of the changes - //ContentService.Saved += (sender, args) => - //{ - // var entity = args.SavedEntities.FirstOrDefault(); - // if (entity != null) - // _previewHub.Clients.All.refreshed(entity.Id); - //}; + _hubContext = hubContext; + } - ContentCacheRefresher.CacheUpdated += (sender, args) => + public void Initialize() + { + // ContentService.Saved is too soon - the content cache is not ready yet, + // so use the content cache refresher event, because when it triggers + // the cache has already been notified of the changes + + ContentCacheRefresher.CacheUpdated += HandleCacheUpdated; + } + + public void Terminate() + { + ContentCacheRefresher.CacheUpdated -= HandleCacheUpdated; + } + + private void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) + { + if (args.MessageType != MessageType.RefreshByPayload) return; + var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject; + var hubContextInstance = _hubContext.Value; + foreach (var payload in payloads) { - if (args.MessageType != MessageType.RefreshByPayload) return; - var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject; - var hubContextInstance = hubContext.Value; - foreach (var payload in payloads) - { - var id = payload.Id; // keep it simple for now, ignore ChangeTypes - hubContextInstance.Clients.All.refreshed(id); - } - }; + var id = payload.Id; // keep it simple for now, ignore ChangeTypes + hubContextInstance.Clients.All.refreshed(id); + } } } } From 4fa43abe2392b941d8cfed9385859b8f8c7c00d5 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 7 Jan 2019 09:45:36 +0100 Subject: [PATCH 08/35] Fix nuspec --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 4d9c8ab037..a673f5d45c 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -95,8 +95,8 @@ - - + + all From 775dd672545dedd99b88a651cd0c2947179a56b1 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 7 Jan 2019 09:45:58 +0100 Subject: [PATCH 09/35] Version 8.0.0-alpha-57 --- src/SolutionInfo.cs | 2 +- src/Umbraco.Web.UI.Client/package-lock.json | 28 ++++++--------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 68d3cb4b6f..c161c81340 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("8.0.0")] -[assembly: AssemblyInformationalVersion("8.0.0-alpha.56")] +[assembly: AssemblyInformationalVersion("8.0.0-alpha.57")] diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 8badea2b2b..7c3fe8b4f9 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -5152,14 +5152,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5174,20 +5172,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5304,8 +5299,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5317,7 +5311,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5332,7 +5325,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5340,14 +5332,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5366,7 +5356,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5447,8 +5436,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5460,7 +5448,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5582,7 +5569,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", From ab11be50a371d618a134903b923b11f96156b086 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 7 Jan 2019 08:31:38 +0100 Subject: [PATCH 10/35] Don't change content app when saving media items --- src/Umbraco.Web.UI.Client/src/views/media/edit.html | 3 ++- .../src/views/media/media.edit.controller.js | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/media/edit.html b/src/Umbraco.Web.UI.Client/src/views/media/edit.html index 2dfc8c967e..be1219f052 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/edit.html @@ -13,7 +13,8 @@ hide-icon="true" hide-description="true" hide-alias="true" - navigation="content.apps"> + navigation="content.apps" + on-select-navigation-item="appChanged(app)"> diff --git a/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js index cc63b5f9f0..19932887fd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js @@ -95,8 +95,11 @@ function mediaEditController($scope, $routeParams, $q, appState, mediaResource, function init() { - // set first app to active - $scope.content.apps[0].active = true; + if (!$scope.app) { + // set first app to active + $scope.content.apps[0].active = true; + $scope.app = $scope.content.apps[0]; + } // setup infinite mode if(infiniteMode) { @@ -207,6 +210,10 @@ function mediaEditController($scope, $routeParams, $q, appState, mediaResource, } }; + $scope.appChanged = function (app) { + $scope.app = app; + } + evts.push(eventsService.on("editors.mediaType.saved", function(name, args) { // if this media item uses the updated media type we need to reload the media item if(args && args.mediaType && args.mediaType.key === $scope.content.contentType.key) { From 12f726842301f80b254f1bdbb7eb06ca2d3cc0e1 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 7 Jan 2019 12:01:53 +0100 Subject: [PATCH 11/35] Also update web.Template.config with latest version of Microsoft.CodeDom.Providers.DotNetCompilerPlatform --- src/Umbraco.Web.UI/web.Template.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 50319370e9..6bc1216d34 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -303,11 +303,11 @@ From d231db8ef25455c2d1f291b9b707e4d95a251a9f Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Mon, 7 Jan 2019 12:41:07 +0100 Subject: [PATCH 12/35] Add disabled state to toggle (#3967) --- .../components/buttons/umbtoggle.directive.js | 4 ++++ .../src/less/components/buttons/umb-toggle.less | 10 ++++++++-- .../src/less/components/users/umb-permission.less | 10 ++++++---- .../src/views/components/buttons/umb-toggle.html | 2 +- .../src/views/languages/edit.html | 3 ++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js index e3c4cbf40c..c2c9ec068b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js @@ -18,6 +18,7 @@ @param {boolean} checked Set to true or false to toggle the switch. +@param {boolean} disabled Set to true or false to disable the switch. @param {callback} onClick The function which should be called when the toggle is clicked. @param {string=} showLabels Set to true or false to show a "On" or "Off" label next to the switch. @param {string=} labelOn Set a custom label for when the switched is turned on. It will default to "On". @@ -115,6 +118,7 @@ templateUrl: 'views/components/buttons/umb-toggle.html', scope: { checked: "=", + disabled: "=", onClick: "&", labelOn: "@?", labelOff: "@?", diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less index 150963cbb2..4c30ae583c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less @@ -28,7 +28,8 @@ .umb-toggle__toggle { cursor: pointer; - display: inline-block; + align-items: center; + display: flex; width: 48px; height: 24px; background: @gray-8; @@ -41,6 +42,11 @@ background-color: @green; } +.umb-toggle--disabled .umb-toggle__toggle { + cursor: not-allowed; + opacity: 0.8; +} + .umb-toggle--checked .umb-toggle__handler { transform: translate3d(24px, 0, 0) rotate(0); } @@ -63,7 +69,7 @@ .umb-toggle__icon { position: absolute; - top: 3px; + line-height: 1em; text-decoration: none; transition: all 0.2s ease; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-permission.less b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-permission.less index f5a81e3393..0d74986d65 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-permission.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-permission.less @@ -4,10 +4,6 @@ padding: 7px 0; } -.umb-permission--disabled { - opacity: 0.8; -} - .umb-permission:last-of-type { border-bottom: none; } @@ -25,6 +21,12 @@ cursor: pointer; } +.umb-permission--disabled .umb-permission__toggle, +.umb-permission--disabled .umb-permission__content { + cursor: not-allowed; + opacity: 0.8; +} + .umb-permission__description { font-size: 13px; color: @gray-4; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html index bc5c114bb6..c8039448fd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html @@ -1,4 +1,4 @@ -