Refactor of dashboards
* Remove dashboards from Configs().Dashboards * Remove dashboard.config XML file & associated code reading from XML * Load Dashboards from TypeLoader into a CollectionBuilder * Load merge/concat C# Dashboard Types with package.manifest * Add buildercolletion to an extension method on Composition
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.Configuration.HealthChecks;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
@@ -22,9 +21,6 @@ namespace Umbraco.Core
|
||||
public static IUmbracoSettingsSection Settings(this Configs configs)
|
||||
=> configs.GetConfig<IUmbracoSettingsSection>();
|
||||
|
||||
public static IDashboardSection Dashboards(this Configs configs)
|
||||
=> configs.GetConfig<IDashboardSection>();
|
||||
|
||||
public static IHealthChecks HealthChecks(this Configs configs)
|
||||
=> configs.GetConfig<IHealthChecks>();
|
||||
|
||||
@@ -40,7 +36,6 @@ namespace Umbraco.Core
|
||||
|
||||
configs.Add<IGlobalSettings>(() => new GlobalSettings());
|
||||
configs.Add<IUmbracoSettingsSection>("umbracoConfiguration/settings");
|
||||
configs.Add<IDashboardSection>("umbracoConfiguration/dashBoard");
|
||||
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
|
||||
|
||||
configs.Add(() => new CoreDebug());
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AccessElement : RawXmlConfigurationElement, IAccess
|
||||
{
|
||||
public AccessElement()
|
||||
{ }
|
||||
|
||||
public AccessElement(XElement rawXml)
|
||||
: base(rawXml)
|
||||
{ }
|
||||
|
||||
public IEnumerable<IAccessRule> Rules
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = new List<AccessRule>();
|
||||
if (RawXml == null) return result;
|
||||
|
||||
result.AddRange(RawXml.Elements("deny").Select(x => new AccessRule {Type = AccessRuleType.Deny, Value = x.Value }));
|
||||
result.AddRange(RawXml.Elements("grant").Select(x => new AccessRule { Type = AccessRuleType.Grant, Value = x.Value }));
|
||||
result.AddRange(RawXml.Elements("grantBySection").Select(x => new AccessRule { Type = AccessRuleType.GrantBySection, Value = x.Value }));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AreaCollection : ConfigurationElementCollection, IEnumerable<IArea>
|
||||
{
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new AreaElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((AreaElement) element).Value;
|
||||
}
|
||||
|
||||
IEnumerator<IArea> IEnumerable<IArea>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as IArea;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AreaElement : InnerTextConfigurationElement<string>, IArea
|
||||
{
|
||||
string IArea.AreaName
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AreasElement : ConfigurationElement
|
||||
{
|
||||
[ConfigurationCollection(typeof(SectionCollection), AddItemName = "area")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public AreaCollection AreaCollection
|
||||
{
|
||||
get { return (AreaCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class ControlCollection : ConfigurationElementCollection, IEnumerable<IDashboardControl>
|
||||
{
|
||||
internal void Add(ControlElement c)
|
||||
{
|
||||
BaseAdd(c);
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new ControlElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((ControlElement)element).ControlPath;
|
||||
}
|
||||
|
||||
IEnumerator<IDashboardControl> IEnumerable<IDashboardControl>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as IDashboardControl;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
|
||||
internal class ControlElement : RawXmlConfigurationElement, IDashboardControl
|
||||
{
|
||||
public string PanelCaption
|
||||
{
|
||||
get
|
||||
{
|
||||
var panelCaption = RawXml.Attribute("panelCaption");
|
||||
return panelCaption == null ? "" : panelCaption.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public AccessElement Access
|
||||
{
|
||||
get
|
||||
{
|
||||
var access = RawXml.Element("access");
|
||||
return access == null ? new AccessElement() : new AccessElement(access);
|
||||
}
|
||||
}
|
||||
|
||||
public string ControlPath
|
||||
{
|
||||
get
|
||||
{
|
||||
//we need to return the first (and only) text element of the children (wtf... who designed this configuration ! :P )
|
||||
var txt = RawXml.Nodes().OfType<XText>().FirstOrDefault();
|
||||
if (txt == null)
|
||||
{
|
||||
throw new ConfigurationErrorsException("The control element must contain a text node indicating the control path");
|
||||
}
|
||||
return txt.Value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
IAccess IDashboardControl.AccessRights => Access;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class DashboardSection : ConfigurationSection, IDashboardSection
|
||||
{
|
||||
[ConfigurationCollection(typeof(SectionCollection), AddItemName = "section")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public SectionCollection SectionCollection
|
||||
{
|
||||
get { return (SectionCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
|
||||
IEnumerable<ISection> IDashboardSection.Sections
|
||||
{
|
||||
get { return SectionCollection; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IAccess
|
||||
{
|
||||
IEnumerable<IAccessRule> Rules { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IArea
|
||||
{
|
||||
string AreaName { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IDashboardControl
|
||||
{
|
||||
string PanelCaption { get; }
|
||||
|
||||
string ControlPath { get; }
|
||||
|
||||
IAccess AccessRights { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IDashboardSection
|
||||
{
|
||||
IEnumerable<ISection> Sections { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IDashboardTab
|
||||
{
|
||||
string Caption { get; }
|
||||
|
||||
IEnumerable<IDashboardControl> Controls { get; }
|
||||
|
||||
IAccess AccessRights { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface ISection
|
||||
{
|
||||
string Alias { get; }
|
||||
|
||||
IEnumerable<string> Areas { get; }
|
||||
|
||||
IEnumerable<IDashboardTab> Tabs { get; }
|
||||
|
||||
IAccess AccessRights { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class SectionCollection : ConfigurationElementCollection, IEnumerable<ISection>
|
||||
{
|
||||
internal void Add(SectionElement c)
|
||||
{
|
||||
BaseAdd(c);
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new SectionElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((SectionElement)element).Alias;
|
||||
}
|
||||
|
||||
IEnumerator<ISection> IEnumerable<ISection>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as ISection;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class SectionElement : ConfigurationElement, ISection
|
||||
{
|
||||
[ConfigurationProperty("alias", IsRequired = true)]
|
||||
public string Alias
|
||||
{
|
||||
get { return (string) this["alias"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("areas", IsRequired = true)]
|
||||
public AreasElement Areas
|
||||
{
|
||||
get { return (AreasElement)this["areas"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("access")]
|
||||
public AccessElement Access
|
||||
{
|
||||
get { return (AccessElement)this["access"]; }
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(SectionCollection), AddItemName = "tab")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public TabCollection TabCollection
|
||||
{
|
||||
get { return (TabCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
|
||||
IEnumerable<IDashboardTab> ISection.Tabs
|
||||
{
|
||||
get { return TabCollection; }
|
||||
}
|
||||
|
||||
IEnumerable<string> ISection.Areas
|
||||
{
|
||||
get { return Areas.AreaCollection.Cast<AreaElement>().Select(x => x.Value); }
|
||||
}
|
||||
|
||||
IAccess ISection.AccessRights
|
||||
{
|
||||
get { return Access; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class TabCollection : ConfigurationElementCollection, IEnumerable<IDashboardTab>
|
||||
{
|
||||
internal void Add(TabElement c)
|
||||
{
|
||||
BaseAdd(c);
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new TabElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((TabElement)element).Caption;
|
||||
}
|
||||
|
||||
IEnumerator<IDashboardTab> IEnumerable<IDashboardTab>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as IDashboardTab;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class TabElement : ConfigurationElement, IDashboardTab
|
||||
{
|
||||
[ConfigurationProperty("caption", IsRequired = true)]
|
||||
public string Caption
|
||||
{
|
||||
get { return (string)this["caption"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("access")]
|
||||
public AccessElement Access
|
||||
{
|
||||
get { return (AccessElement)this["access"]; }
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(ControlCollection), AddItemName = "control")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public ControlCollection ControlCollection
|
||||
{
|
||||
get { return (ControlCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
|
||||
IEnumerable<IDashboardControl> IDashboardTab.Controls
|
||||
{
|
||||
get { return ControlCollection; }
|
||||
}
|
||||
|
||||
IAccess IDashboardTab.AccessRights
|
||||
{
|
||||
get { return Access; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
namespace Umbraco.Core.Dashboards
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements <see cref="IAccessRule"/>.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
namespace Umbraco.Core.Dashboards
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines dashboard access rules type.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
namespace Umbraco.Core.Dashboards
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an access rule.
|
||||
30
src/Umbraco.Core/Dashboards/IDashboardSection.cs
Normal file
30
src/Umbraco.Core/Dashboards/IDashboardSection.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Umbraco.Core.Dashboards
|
||||
{
|
||||
public interface IDashboardSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Display name of the dashboard tab
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Alias to refer to this dashboard via code
|
||||
/// </summary>
|
||||
string Alias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection of sections/application aliases that this dashboard will appear on
|
||||
/// </summary>
|
||||
string[] Sections { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The HTML view to load for the dashboard
|
||||
/// </summary>
|
||||
string View { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Dashboards can be shown/hidden based on access rights
|
||||
/// </summary>
|
||||
IAccessRule[] AccessRules { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
public class ManifestDashboardDefinition
|
||||
public class ManifestDashboardDefinition : IDashboardSection
|
||||
{
|
||||
private string _view;
|
||||
|
||||
@@ -32,5 +32,6 @@ namespace Umbraco.Core.Manifest
|
||||
|
||||
[JsonProperty("access")]
|
||||
public IAccessRule[] AccessRules { get; set; } = Array.Empty<IAccessRule>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,26 +211,6 @@
|
||||
<Compile Include="ConfigsExtensions.cs" />
|
||||
<Compile Include="Configuration\Configs.cs" />
|
||||
<Compile Include="Configuration\CoreDebug.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessRule.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessRuleType.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AreaCollection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AreaElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AreasElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\ControlCollection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\ControlElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\DashboardSection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\IAccess.cs" />
|
||||
<Compile Include="Configuration\Dashboard\IAccessRule.cs" />
|
||||
<Compile Include="Configuration\Dashboard\IArea.cs" />
|
||||
<Compile Include="Configuration\Dashboard\IDashboardControl.cs" />
|
||||
<Compile Include="Configuration\Dashboard\IDashboardSection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\IDashboardTab.cs" />
|
||||
<Compile Include="Configuration\Dashboard\ISection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\SectionCollection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\SectionElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\TabCollection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\TabElement.cs" />
|
||||
<Compile Include="Configuration\FileSystemProviderElement.cs" />
|
||||
<Compile Include="Configuration\FileSystemProviderElementCollection.cs" />
|
||||
<Compile Include="Configuration\FileSystemProvidersSection.cs" />
|
||||
@@ -331,6 +311,10 @@
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Composing\RegisterExtensions.cs" />
|
||||
<Compile Include="ContentVariationExtensions.cs" />
|
||||
<Compile Include="Dashboards\AccessRule.cs" />
|
||||
<Compile Include="Dashboards\AccessRuleType.cs" />
|
||||
<Compile Include="Dashboards\IAccessRule.cs" />
|
||||
<Compile Include="Dashboards\IDashboardSection.cs" />
|
||||
<Compile Include="DisposableObjectSlim.cs" />
|
||||
<Compile Include="Events\ExportedMemberEventArgs.cs" />
|
||||
<Compile Include="Events\RolesEventArgs.cs" />
|
||||
|
||||
@@ -1,123 +1,124 @@
|
||||
using System.Configuration;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Configurations.DashboardSettings
|
||||
{
|
||||
[TestFixture]
|
||||
public class DashboardSettingsTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Init()
|
||||
{
|
||||
var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/DashboardSettings/web.config"));
|
||||
//[Obsolete("Dashboard tests not in config/XML", true)]
|
||||
//[TestFixture]
|
||||
//public class DashboardSettingsTests
|
||||
//{
|
||||
// [SetUp]
|
||||
// public void Init()
|
||||
// {
|
||||
// var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/DashboardSettings/web.config"));
|
||||
|
||||
var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName };
|
||||
var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
|
||||
// var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName };
|
||||
// var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
|
||||
|
||||
SettingsSection = configuration.GetSection("umbracoConfiguration/dashBoard") as DashboardSection;
|
||||
// SettingsSection = configuration.GetSection("umbracoConfiguration/dashBoard") as DashboardSection;
|
||||
|
||||
Assert.IsNotNull(SettingsSection);
|
||||
}
|
||||
// Assert.IsNotNull(SettingsSection);
|
||||
// }
|
||||
|
||||
protected IDashboardSection SettingsSection { get; private set; }
|
||||
// protected IDashboardSection SettingsSection { get; private set; }
|
||||
|
||||
[Test]
|
||||
public void Test_Sections()
|
||||
{
|
||||
Assert.AreEqual(5, SettingsSection.Sections.Count());
|
||||
// [Test]
|
||||
// public void Test_Sections()
|
||||
// {
|
||||
// Assert.AreEqual(5, SettingsSection.Sections.Count());
|
||||
|
||||
Assert.AreEqual("StartupSettingsDashboardSection", SettingsSection.Sections.ElementAt(0).Alias);
|
||||
Assert.AreEqual("StartupDeveloperDashboardSection", SettingsSection.Sections.ElementAt(1).Alias);
|
||||
Assert.AreEqual("StartupMediaDashboardSection", SettingsSection.Sections.ElementAt(2).Alias);
|
||||
Assert.AreEqual("StartupDashboardSection", SettingsSection.Sections.ElementAt(3).Alias);
|
||||
Assert.AreEqual("StartupMemberDashboardSection", SettingsSection.Sections.ElementAt(4).Alias);
|
||||
}
|
||||
// Assert.AreEqual("StartupSettingsDashboardSection", SettingsSection.Sections.ElementAt(0).Alias);
|
||||
// Assert.AreEqual("StartupDeveloperDashboardSection", SettingsSection.Sections.ElementAt(1).Alias);
|
||||
// Assert.AreEqual("StartupMediaDashboardSection", SettingsSection.Sections.ElementAt(2).Alias);
|
||||
// Assert.AreEqual("StartupDashboardSection", SettingsSection.Sections.ElementAt(3).Alias);
|
||||
// Assert.AreEqual("StartupMemberDashboardSection", SettingsSection.Sections.ElementAt(4).Alias);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Section_Area()
|
||||
{
|
||||
Assert.AreEqual("settings", SettingsSection.Sections.ElementAt(0).Areas.First());
|
||||
Assert.AreEqual("developer", SettingsSection.Sections.ElementAt(1).Areas.First());
|
||||
Assert.AreEqual("media", SettingsSection.Sections.ElementAt(2).Areas.First());
|
||||
Assert.AreEqual("content", SettingsSection.Sections.ElementAt(3).Areas.First());
|
||||
Assert.AreEqual("default", SettingsSection.Sections.ElementAt(4).Areas.First());
|
||||
Assert.AreEqual("member", SettingsSection.Sections.ElementAt(4).Areas.Last());
|
||||
}
|
||||
// [Test]
|
||||
// public void Test_Section_Area()
|
||||
// {
|
||||
// Assert.AreEqual("settings", SettingsSection.Sections.ElementAt(0).Areas.First());
|
||||
// Assert.AreEqual("developer", SettingsSection.Sections.ElementAt(1).Areas.First());
|
||||
// Assert.AreEqual("media", SettingsSection.Sections.ElementAt(2).Areas.First());
|
||||
// Assert.AreEqual("content", SettingsSection.Sections.ElementAt(3).Areas.First());
|
||||
// Assert.AreEqual("default", SettingsSection.Sections.ElementAt(4).Areas.First());
|
||||
// Assert.AreEqual("member", SettingsSection.Sections.ElementAt(4).Areas.Last());
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Section_Access()
|
||||
{
|
||||
// [Test]
|
||||
// public void Test_Section_Access()
|
||||
// {
|
||||
|
||||
Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.Count());
|
||||
// Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.Count());
|
||||
|
||||
Assert.AreEqual("translator", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Value);
|
||||
Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Type);
|
||||
Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Value);
|
||||
Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Type);
|
||||
Assert.AreEqual("world", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Value);
|
||||
Assert.AreEqual(AccessRuleType.GrantBySection, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Type);
|
||||
}
|
||||
// Assert.AreEqual("translator", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Value);
|
||||
// Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Type);
|
||||
// Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Value);
|
||||
// Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Type);
|
||||
// Assert.AreEqual("world", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Value);
|
||||
// Assert.AreEqual(AccessRuleType.GrantBySection, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Type);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Section_Tabs()
|
||||
{
|
||||
//Element 0 Alias "StartupSettingsDashboardSection"
|
||||
Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.Count());
|
||||
// [Test]
|
||||
// public void Test_Section_Tabs()
|
||||
// {
|
||||
// //Element 0 Alias "StartupSettingsDashboardSection"
|
||||
// Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.Count());
|
||||
|
||||
//Element 1 Alias "StartupDeveloperDashboardSection"
|
||||
Assert.AreEqual(1, SettingsSection.Sections.ElementAt(1).Tabs.Count());
|
||||
// //Element 1 Alias "StartupDeveloperDashboardSection"
|
||||
// Assert.AreEqual(1, SettingsSection.Sections.ElementAt(1).Tabs.Count());
|
||||
|
||||
//Element 2 Alias "StartupMediaDashboardSection"
|
||||
Assert.AreEqual(2, SettingsSection.Sections.ElementAt(2).Tabs.Count());
|
||||
// //Element 2 Alias "StartupMediaDashboardSection"
|
||||
// Assert.AreEqual(2, SettingsSection.Sections.ElementAt(2).Tabs.Count());
|
||||
|
||||
//Element 3 Alias "StartupDashboardSection"
|
||||
Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).Tabs.Count());
|
||||
// //Element 3 Alias "StartupDashboardSection"
|
||||
// Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).Tabs.Count());
|
||||
|
||||
//Element 4 Alias "StartupMemberDashboardSection"
|
||||
Assert.AreEqual(1, SettingsSection.Sections.ElementAt(4).Tabs.Count());
|
||||
// //Element 4 Alias "StartupMemberDashboardSection"
|
||||
// Assert.AreEqual(1, SettingsSection.Sections.ElementAt(4).Tabs.Count());
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Tab()
|
||||
{
|
||||
Assert.AreEqual("Get Started", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Caption);
|
||||
Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.Count());
|
||||
}
|
||||
// [Test]
|
||||
// public void Test_Tab()
|
||||
// {
|
||||
// Assert.AreEqual("Get Started", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Caption);
|
||||
// Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.Count());
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Tab_Access()
|
||||
{
|
||||
Assert.AreEqual(1, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.Count());
|
||||
Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Type);
|
||||
Assert.AreEqual("admin", SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Value);
|
||||
}
|
||||
// [Test]
|
||||
// public void Test_Tab_Access()
|
||||
// {
|
||||
// Assert.AreEqual(1, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.Count());
|
||||
// Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Type);
|
||||
// Assert.AreEqual("admin", SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Value);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Control()
|
||||
{
|
||||
Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).PanelCaption);
|
||||
Assert.AreEqual("views/dashboard/settings/settingsdashboardintro.html",
|
||||
SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).ControlPath);
|
||||
// [Test]
|
||||
// public void Test_Control()
|
||||
// {
|
||||
// Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).PanelCaption);
|
||||
// Assert.AreEqual("views/dashboard/settings/settingsdashboardintro.html",
|
||||
// SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).ControlPath);
|
||||
|
||||
Assert.AreEqual("", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).PanelCaption);
|
||||
Assert.AreEqual("views/dashboard/settings/settingsdashboardvideos.html",
|
||||
SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).ControlPath);
|
||||
}
|
||||
// Assert.AreEqual("", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).PanelCaption);
|
||||
// Assert.AreEqual("views/dashboard/settings/settingsdashboardvideos.html",
|
||||
// SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).ControlPath);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void Test_Control_Access()
|
||||
{
|
||||
Assert.AreEqual(2, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.Count());
|
||||
Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Type);
|
||||
Assert.AreEqual("editor", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Value);
|
||||
Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Type);
|
||||
Assert.AreEqual("writer", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Value);
|
||||
}
|
||||
}
|
||||
// [Test]
|
||||
// public void Test_Control_Access()
|
||||
// {
|
||||
// Assert.AreEqual(2, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.Count());
|
||||
// Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Type);
|
||||
// Assert.AreEqual("editor", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Value);
|
||||
// Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Type);
|
||||
// Assert.AreEqual("writer", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Value);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.PropertyEditors.Validators;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Tests.Manifest
|
||||
{
|
||||
|
||||
96
src/Umbraco.Web.UI.Client/package-lock.json
generated
96
src/Umbraco.Web.UI.Client/package-lock.json
generated
@@ -937,7 +937,7 @@
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
|
||||
"integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -955,7 +955,7 @@
|
||||
},
|
||||
"ansi-escapes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
|
||||
"integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
|
||||
"dev": true
|
||||
},
|
||||
@@ -1170,7 +1170,7 @@
|
||||
"array-slice": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
|
||||
"integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=",
|
||||
"integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
|
||||
"dev": true
|
||||
},
|
||||
"array-sort": {
|
||||
@@ -1216,7 +1216,7 @@
|
||||
"arraybuffer.slice": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
||||
"integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=",
|
||||
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
|
||||
"dev": true
|
||||
},
|
||||
"asap": {
|
||||
@@ -1269,7 +1269,7 @@
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
|
||||
"dev": true
|
||||
},
|
||||
"asynckit": {
|
||||
@@ -2379,7 +2379,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -2459,7 +2459,7 @@
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||
"dev": true
|
||||
},
|
||||
"continuable-cache": {
|
||||
@@ -2502,7 +2502,7 @@
|
||||
"core-js": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||
"integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=",
|
||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
@@ -3425,7 +3425,7 @@
|
||||
"doctrine": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
"integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=",
|
||||
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esutils": "^2.0.2"
|
||||
@@ -3953,7 +3953,7 @@
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -3989,7 +3989,7 @@
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -4153,7 +4153,7 @@
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
@@ -4248,7 +4248,7 @@
|
||||
"eslint-scope": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
|
||||
"integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=",
|
||||
"integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
@@ -4258,13 +4258,13 @@
|
||||
"eslint-utils": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
|
||||
"integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=",
|
||||
"integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
"integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=",
|
||||
"integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
|
||||
"dev": true
|
||||
},
|
||||
"espree": {
|
||||
@@ -4287,7 +4287,7 @@
|
||||
"esquery": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
|
||||
"integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=",
|
||||
"integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estraverse": "^4.0.0"
|
||||
@@ -4296,7 +4296,7 @@
|
||||
"esrecurse": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
|
||||
"integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=",
|
||||
"integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estraverse": "^4.1.0"
|
||||
@@ -4356,7 +4356,7 @@
|
||||
"eventemitter3": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
|
||||
"integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=",
|
||||
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==",
|
||||
"dev": true
|
||||
},
|
||||
"exec-buffer": {
|
||||
@@ -4571,7 +4571,7 @@
|
||||
"fill-range": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
|
||||
"integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
|
||||
"integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^2.1.0",
|
||||
@@ -5891,7 +5891,7 @@
|
||||
"global-modules": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
|
||||
"integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
|
||||
"integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"global-prefix": "^1.0.1",
|
||||
@@ -6461,7 +6461,7 @@
|
||||
"gulp-eslint": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz",
|
||||
"integrity": "sha1-KiaECV93Syz3kxAmIHjFbMehK1I=",
|
||||
"integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint": "^5.0.1",
|
||||
@@ -7415,7 +7415,7 @@
|
||||
"has-binary2": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
|
||||
"integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
|
||||
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isarray": "2.0.1"
|
||||
@@ -7566,7 +7566,7 @@
|
||||
"http-proxy": {
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
|
||||
"integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=",
|
||||
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "^3.0.0",
|
||||
@@ -7860,7 +7860,7 @@
|
||||
"is-absolute": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
|
||||
"integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=",
|
||||
"integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-relative": "^1.0.0",
|
||||
@@ -8155,7 +8155,7 @@
|
||||
"is-relative": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
|
||||
"integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=",
|
||||
"integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-unc-path": "^1.0.0"
|
||||
@@ -8164,7 +8164,7 @@
|
||||
"is-resolvable": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
|
||||
"integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=",
|
||||
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-retry-allowed": {
|
||||
@@ -8212,7 +8212,7 @@
|
||||
"is-unc-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
|
||||
"integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=",
|
||||
"integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"unc-path-regex": "^0.1.2"
|
||||
@@ -8369,7 +8369,7 @@
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"json-stable-stringify-without-jsonify": {
|
||||
@@ -8496,7 +8496,7 @@
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -9146,7 +9146,7 @@
|
||||
"make-iterator": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
|
||||
"integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=",
|
||||
"integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"kind-of": "^6.0.2"
|
||||
@@ -9327,7 +9327,7 @@
|
||||
"mimic-fn": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
|
||||
"integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=",
|
||||
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
@@ -12855,7 +12855,7 @@
|
||||
"pluralize": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
|
||||
"integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=",
|
||||
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
|
||||
"dev": true
|
||||
},
|
||||
"posix-character-classes": {
|
||||
@@ -13345,7 +13345,7 @@
|
||||
"qjobs": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
|
||||
"integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
|
||||
"integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
@@ -13541,7 +13541,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14039,7 +14039,7 @@
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"sax": {
|
||||
@@ -14226,7 +14226,7 @@
|
||||
"setprototypeof": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||
"integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=",
|
||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"shebang-command": {
|
||||
@@ -14516,7 +14516,7 @@
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -14796,7 +14796,7 @@
|
||||
"stream-consume": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz",
|
||||
"integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=",
|
||||
"integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==",
|
||||
"dev": true
|
||||
},
|
||||
"stream-shift": {
|
||||
@@ -14808,7 +14808,7 @@
|
||||
"streamroller": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz",
|
||||
"integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=",
|
||||
"integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"date-format": "^1.2.0",
|
||||
@@ -14835,7 +14835,7 @@
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
@@ -14850,7 +14850,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
@@ -14867,7 +14867,7 @@
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
@@ -15409,7 +15409,7 @@
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
@@ -15573,7 +15573,7 @@
|
||||
"type-is": {
|
||||
"version": "1.6.16",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
|
||||
"integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=",
|
||||
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
@@ -15615,7 +15615,7 @@
|
||||
"ultron": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
||||
"integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=",
|
||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
|
||||
"dev": true
|
||||
},
|
||||
"unc-path-regex": {
|
||||
@@ -15777,13 +15777,13 @@
|
||||
"upath": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
|
||||
"integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0=",
|
||||
"integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
"integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=",
|
||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
@@ -16218,7 +16218,7 @@
|
||||
"ws": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
|
||||
"integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=",
|
||||
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0",
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
<div ng-repeat="property in tab.properties">
|
||||
|
||||
<div class="clearfix">
|
||||
<h3 ng-show="property.caption">{{property.caption}}</h3>
|
||||
<div ng-include="property.path"></div>
|
||||
<div ng-include="property.view"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
<Content Include="App_Plugins\ModelsBuilder\modelsbuilder.controller.js" />
|
||||
<Content Include="App_Plugins\ModelsBuilder\modelsbuilder.htm" />
|
||||
<Content Include="App_Plugins\ModelsBuilder\modelsbuilder.resource.js" />
|
||||
<Content Include="App_Plugins\Test\test.html" />
|
||||
<Content Include="Config\grid.editors.config.js" />
|
||||
<Content Include="Config\Lang\cs-CZ.user.xml" />
|
||||
<Content Include="Config\Lang\da-DK.user.xml" />
|
||||
@@ -205,6 +206,7 @@
|
||||
<Content Include="Config\Splashes\noNodes.aspx" />
|
||||
<Content Include="Umbraco\Install\Views\Web.config" />
|
||||
<Content Include="App_Plugins\ModelsBuilder\package.manifest" />
|
||||
<Content Include="App_Plugins\Test\package.manifest" />
|
||||
<None Include="Config\404handlers.Release.config">
|
||||
<DependentUpon>404handlers.config</DependentUpon>
|
||||
</None>
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
|
||||
<section alias="RedirectUrlManagement">
|
||||
<areas>
|
||||
<area>content</area>
|
||||
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Tour;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.Dashboards;
|
||||
|
||||
// the namespace here is intentional - although defined in Umbraco.Web assembly,
|
||||
// this class should be visible when using Umbraco.Core.Components, alongside
|
||||
@@ -92,6 +93,13 @@ namespace Umbraco.Core.Components
|
||||
public static BackOfficeSectionCollectionBuilder Sections(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<BackOfficeSectionCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the backoffice dashboards collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static DashboardCollectionBuilder Dashboards(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<DashboardCollectionBuilder>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Uniques
|
||||
|
||||
38
src/Umbraco.Web/Dashboards/ContentDashboard.cs
Normal file
38
src/Umbraco.Web/Dashboards/ContentDashboard.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(10)]
|
||||
//[HideFromTypeFinder]
|
||||
[DataContract]
|
||||
public class ContentDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Get Started";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "contentIntro";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "content" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/default/startupdashboardintro.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO: WB Not convinced these rules work correctly?!
|
||||
var rules = new List<IAccessRule>();
|
||||
rules.Add(new AccessRule { Type = AccessRuleType.Deny, Value = "translator" });
|
||||
rules.Add(new AccessRule { Type = AccessRuleType.Grant, Value = "admin" });
|
||||
return rules.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/Umbraco.Web/Dashboards/DashboardCollection.cs
Normal file
13
src/Umbraco.Web/Dashboards/DashboardCollection.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
public class DashboardCollection : BuilderCollectionBase<IDashboardSection>
|
||||
{
|
||||
public DashboardCollection(IEnumerable<IDashboardSection> items)
|
||||
: base(items)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
24
src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs
Normal file
24
src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
public class DashboardCollectionBuilder : WeightedCollectionBuilderBase<DashboardCollectionBuilder, DashboardCollection, IDashboardSection>
|
||||
{
|
||||
protected override DashboardCollectionBuilder This => this;
|
||||
|
||||
protected override IEnumerable<IDashboardSection> CreateItems(IFactory factory)
|
||||
{
|
||||
// get the manifest parser just-in-time - injecting it in the ctor would mean that
|
||||
// simply getting the builder in order to configure the collection, would require
|
||||
// its dependencies too, and that can create cycles or other oddities
|
||||
var manifestParser = factory.GetInstance<ManifestParser>();
|
||||
|
||||
//TODO WB: We will need to re-sort items from package manifest with the C# Types
|
||||
return base.CreateItems(factory).Concat(manifestParser.Manifest.Dashboards);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Web/Dashboards/ExamineDashboard.cs
Normal file
29
src/Umbraco.Web/Dashboards/ExamineDashboard.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(20)]
|
||||
[DataContract]
|
||||
public class ExamineDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Examine Management";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "settingsExamine";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "settings" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/settings/examinemanagement.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
27
src/Umbraco.Web/Dashboards/FormsDashboard.cs
Normal file
27
src/Umbraco.Web/Dashboards/FormsDashboard.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(10)]
|
||||
[DataContract]
|
||||
public class FormsDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Install Umbraco Forms";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "formsInstall";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "forms" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/forms/formsdashboardintro.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs
Normal file
29
src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(50)]
|
||||
[DataContract]
|
||||
public class HealthCheckDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name="name")]
|
||||
public string Name => "Health Check";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "settingsHealthCheck";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "settings" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/settings/healthcheck.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
27
src/Umbraco.Web/Dashboards/MediaDashboard.cs
Normal file
27
src/Umbraco.Web/Dashboards/MediaDashboard.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(10)]
|
||||
[DataContract]
|
||||
public class MediaDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Content";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "mediaFolderBrowser";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "media" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/media/mediafolderbrowser.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
}
|
||||
27
src/Umbraco.Web/Dashboards/MembersDashboard.cs
Normal file
27
src/Umbraco.Web/Dashboards/MembersDashboard.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(10)]
|
||||
[DataContract]
|
||||
public class MembersDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Get Started";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "memberIntro";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "member" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/members/membersdashboardvideos.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs
Normal file
29
src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(40)]
|
||||
[DataContract]
|
||||
public class ModelsBuilderDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Models Builder";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "settingsModelsBuilder";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "settings" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "/App_Plugins/ModelsBuilder/modelsbuilder.htm";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
29
src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs
Normal file
29
src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(30)]
|
||||
[DataContract]
|
||||
public class PublishedStatusDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Published Status";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "settingsPublishedStatus";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "settings" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/settings/publishedstatus.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
27
src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs
Normal file
27
src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(20)]
|
||||
[DataContract]
|
||||
public class RedirectUrlDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Redirect URL Management";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "contentRedirectManager";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "content" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/content/redirecturls.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
}
|
||||
27
src/Umbraco.Web/Dashboards/SettingsDashboards.cs
Normal file
27
src/Umbraco.Web/Dashboards/SettingsDashboards.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
|
||||
namespace Umbraco.Web.Dashboards
|
||||
{
|
||||
[Weight(10)]
|
||||
[DataContract]
|
||||
public class SettingsDashboard : IDashboardSection
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name => "Welcome";
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias => "settingsWelcome";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string[] Sections => new string[] { "settings" };
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View => "views/dashboard/settings/settingsdashboardintro.html";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ using Umbraco.Web.WebApi.Filters;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Web.Services;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -27,7 +29,7 @@ namespace Umbraco.Web.Editors
|
||||
[WebApi.UmbracoAuthorize]
|
||||
public class DashboardController : UmbracoApiController
|
||||
{
|
||||
private readonly Dashboards _dashboards;
|
||||
private readonly IDashboardService _dashboardService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DashboardController"/> with auto dependencies.
|
||||
@@ -38,10 +40,10 @@ namespace Umbraco.Web.Editors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DashboardController"/> with all its dependencies.
|
||||
/// </summary>
|
||||
public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards)
|
||||
public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService)
|
||||
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
|
||||
{
|
||||
_dashboards = dashboards;
|
||||
_dashboardService = dashboardService;
|
||||
}
|
||||
|
||||
//we have just one instance of HttpClient shared for the entire application
|
||||
@@ -79,7 +81,7 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
Logger.Error<DashboardController>(ex.InnerException ?? ex, "Error getting dashboard content from '{Url}'", url);
|
||||
Logger.Error<DashboardController>(ex.InnerException ?? ex, "Error getting dashboard content from {Url}", url);
|
||||
|
||||
//it's still new JObject() - we return it like this to avoid error codes which triggers UI warnings
|
||||
AppCaches.RuntimeCache.InsertCacheItem<JObject>(key, () => result, new TimeSpan(0, 5, 0));
|
||||
@@ -117,7 +119,7 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
Logger.Error<DashboardController>(ex.InnerException ?? ex, "Error getting dashboard CSS from '{Url}'", url);
|
||||
Logger.Error<DashboardController>(ex.InnerException ?? ex, "Error getting dashboard CSS from {Url}", url);
|
||||
|
||||
//it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings
|
||||
AppCaches.RuntimeCache.InsertCacheItem<string>(key, () => result, new TimeSpan(0, 5, 0));
|
||||
@@ -132,9 +134,9 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
[ValidateAngularAntiForgeryToken]
|
||||
[OutgoingEditorModelEvent]
|
||||
public IEnumerable<Tab<DashboardControl>> GetDashboard(string section)
|
||||
public IEnumerable<Tab<IDashboardSection>> GetDashboard(string section)
|
||||
{
|
||||
return _dashboards.GetDashboards(section, Security.CurrentUser);
|
||||
return _dashboardService.GetDashboards(section, Security.CurrentUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Services;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
public class Dashboards
|
||||
{
|
||||
private readonly ISectionService _sectionService;
|
||||
private readonly IDashboardSection _dashboardSection;
|
||||
private readonly ManifestParser _manifestParser;
|
||||
|
||||
public Dashboards(ISectionService sectionService, IDashboardSection dashboardSection, ManifestParser manifestParser)
|
||||
{
|
||||
_sectionService = sectionService ?? throw new ArgumentNullException(nameof(sectionService));
|
||||
_dashboardSection = dashboardSection;
|
||||
_manifestParser = manifestParser;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all dashboards, organized by section, for a user.
|
||||
/// </summary>
|
||||
public IDictionary<string, IEnumerable<Tab<DashboardControl>>> GetDashboards(IUser currentUser)
|
||||
{
|
||||
return _sectionService.GetSections().ToDictionary(x => x.Alias, x => GetDashboards(x.Alias, currentUser));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns dashboards for a specific section, for a user.
|
||||
/// </summary>
|
||||
public IEnumerable<Tab<DashboardControl>> GetDashboards(string section, IUser currentUser)
|
||||
{
|
||||
var tabId = 1;
|
||||
var configDashboards = GetDashboardsFromConfig(ref tabId, section, currentUser);
|
||||
var pluginDashboards = GetDashboardsFromPlugins(ref tabId, section, currentUser);
|
||||
|
||||
// merge dashboards
|
||||
// both collections contain tab.alias -> controls
|
||||
var dashboards = configDashboards;
|
||||
|
||||
// until now, it was fine to have duplicate tab.aliases in configDashboard
|
||||
// so... the rule should be - just merge whatever we get, don't be clever
|
||||
dashboards.AddRange(pluginDashboards);
|
||||
|
||||
// re-sort by id
|
||||
dashboards.Sort((tab1, tab2) => tab1.Id > tab2.Id ? 1 : 0);
|
||||
|
||||
// re-assign ids (why?)
|
||||
var i = 1;
|
||||
foreach (var tab in dashboards)
|
||||
{
|
||||
tab.Id = i++;
|
||||
tab.IsActive = tab.Id == 1;
|
||||
}
|
||||
|
||||
return configDashboards;
|
||||
}
|
||||
|
||||
// note:
|
||||
// in dashboard.config we have 'sections' which define 'tabs' for 'areas'
|
||||
// and 'areas' are the true UI sections - and each tab can have more than
|
||||
// one control
|
||||
// in a manifest, we directly have 'dashboards' which map to a unique
|
||||
// control in a tab
|
||||
|
||||
// gets all tabs & controls from the config file
|
||||
private List<Tab<DashboardControl>> GetDashboardsFromConfig(ref int tabId, string section, IUser currentUser)
|
||||
{
|
||||
var tabs = new List<Tab<DashboardControl>>();
|
||||
|
||||
// disable packages section dashboard
|
||||
if (section == "packages") return tabs;
|
||||
|
||||
foreach (var dashboardSection in _dashboardSection.Sections.Where(x => x.Areas.InvariantContains(section)))
|
||||
{
|
||||
// validate access to this section
|
||||
if (!DashboardSecurity.AuthorizeAccess(dashboardSection, currentUser, _sectionService))
|
||||
continue;
|
||||
|
||||
foreach (var tab in dashboardSection.Tabs)
|
||||
{
|
||||
// validate access to this tab
|
||||
if (!DashboardSecurity.AuthorizeAccess(tab, currentUser, _sectionService))
|
||||
continue;
|
||||
|
||||
var dashboardControls = new List<DashboardControl>();
|
||||
|
||||
foreach (var control in tab.Controls)
|
||||
{
|
||||
// validate access to this control
|
||||
if (!DashboardSecurity.AuthorizeAccess(control, currentUser, _sectionService))
|
||||
continue;
|
||||
|
||||
// create and add control
|
||||
var dashboardControl = new DashboardControl
|
||||
{
|
||||
Caption = control.PanelCaption,
|
||||
Path = IOHelper.FindFile(control.ControlPath.Trim())
|
||||
};
|
||||
|
||||
if (dashboardControl.Path.InvariantEndsWith(".ascx"))
|
||||
throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported.");
|
||||
|
||||
dashboardControls.Add(dashboardControl);
|
||||
}
|
||||
|
||||
// create and add tab
|
||||
tabs.Add(new Tab<DashboardControl>
|
||||
{
|
||||
Id = tabId++,
|
||||
Alias = tab.Caption.ToSafeAlias(),
|
||||
Label = tab.Caption,
|
||||
Properties = dashboardControls
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private List<Tab<DashboardControl>> GetDashboardsFromPlugins(ref int tabId, string section, IUser currentUser)
|
||||
{
|
||||
var tabs = new List<Tab<DashboardControl>>();
|
||||
|
||||
foreach (var dashboard in _manifestParser.Manifest.Dashboards.Where(x => x.Sections.InvariantContains(section)).OrderBy(x => x.Weight))
|
||||
{
|
||||
// validate access
|
||||
if (!DashboardSecurity.CheckUserAccessByRules(currentUser, _sectionService, dashboard.AccessRules))
|
||||
continue;
|
||||
|
||||
var dashboardControl = new DashboardControl
|
||||
{
|
||||
Caption = "",
|
||||
Path = IOHelper.FindFile(dashboard.View.Trim())
|
||||
};
|
||||
|
||||
if (dashboardControl.Path.InvariantEndsWith(".ascx"))
|
||||
throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported.");
|
||||
|
||||
tabs.Add(new Tab<DashboardControl>
|
||||
{
|
||||
Id = tabId++,
|
||||
Alias = dashboard.Alias.ToSafeAlias(),
|
||||
Label = dashboard.Name,
|
||||
Properties = new[] { dashboardControl }
|
||||
});
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Http.Filters;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
@@ -14,9 +15,9 @@ namespace Umbraco.Web.Editors
|
||||
public static event TypedEventHandler<HttpActionExecutedContext, EditorModelEventArgs<MediaItemDisplay>> SendingMediaModel;
|
||||
public static event TypedEventHandler<HttpActionExecutedContext, EditorModelEventArgs<MemberDisplay>> SendingMemberModel;
|
||||
public static event TypedEventHandler<HttpActionExecutedContext, EditorModelEventArgs<UserDisplay>> SendingUserModel;
|
||||
public static event TypedEventHandler<HttpActionExecutedContext, EditorModelEventArgs<IEnumerable<Tab<DashboardControl>>>> SendingDashboardModel;
|
||||
public static event TypedEventHandler<HttpActionExecutedContext, EditorModelEventArgs<IEnumerable<Tab<IDashboardSection>>>> SendingDashboardModel;
|
||||
|
||||
private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs<IEnumerable<Tab<DashboardControl>>> e)
|
||||
private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs<IEnumerable<Tab<IDashboardSection>>> e)
|
||||
{
|
||||
var handler = SendingDashboardModel;
|
||||
handler?.Invoke(sender, e);
|
||||
@@ -65,8 +66,8 @@ namespace Umbraco.Web.Editors
|
||||
if (e.Model is UserDisplay)
|
||||
OnSendingUserModel(sender, new EditorModelEventArgs<UserDisplay>(e));
|
||||
|
||||
if (e.Model is IEnumerable<Tab<DashboardControl>>)
|
||||
OnSendingDashboardModel(sender, new EditorModelEventArgs<IEnumerable<Tab<DashboardControl>>>(e));
|
||||
if (e.Model is IEnumerable<IDashboardSection>)
|
||||
OnSendingDashboardModel(sender, new EditorModelEventArgs<IEnumerable<Tab<IDashboardSection>>>(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,15 +22,15 @@ namespace Umbraco.Web.Editors
|
||||
[PluginController("UmbracoApi")]
|
||||
public class SectionController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly Dashboards _dashboards;
|
||||
private readonly IDashboardService _dashboardService;
|
||||
private readonly ISectionService _sectionService;
|
||||
private readonly ITreeService _treeService;
|
||||
|
||||
public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState,
|
||||
Dashboards dashboards, ISectionService sectionService, ITreeService treeService)
|
||||
IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService)
|
||||
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
|
||||
{
|
||||
_dashboards = dashboards;
|
||||
_dashboardService = dashboardService;
|
||||
_sectionService = sectionService;
|
||||
_treeService = treeService;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Web.Editors
|
||||
ControllerContext = ControllerContext
|
||||
};
|
||||
|
||||
var dashboards = _dashboards.GetDashboards(Security.CurrentUser);
|
||||
var dashboards = _dashboardService.GetDashboards(Security.CurrentUser);
|
||||
|
||||
//now we can add metadata for each section so that the UI knows if there's actually anything at all to render for
|
||||
//a dashboard for a given section, then the UI can deal with it accordingly (i.e. redirect to the first tree)
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
[DataContract(Name = "control", Namespace = "")]
|
||||
public class DashboardControl
|
||||
{
|
||||
[DataMember(Name = "path")]
|
||||
public string Path { get; set; }
|
||||
|
||||
[DataMember(Name = "caption")]
|
||||
public string Caption { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using Microsoft.AspNet.SignalR;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
@@ -17,6 +18,7 @@ using Umbraco.Web.Actions;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.Composing.Composers;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Dashboards;
|
||||
using Umbraco.Web.Dictionary;
|
||||
using Umbraco.Web.Editors;
|
||||
using Umbraco.Web.Features;
|
||||
@@ -95,14 +97,13 @@ namespace Umbraco.Web.Runtime
|
||||
composition.RegisterUnique<ITreeService, TreeService>();
|
||||
composition.RegisterUnique<ISectionService, SectionService>();
|
||||
|
||||
composition.RegisterUnique<IDashboardService, DashboardService>();
|
||||
|
||||
composition.RegisterUnique<IExamineManager>(factory => ExamineManager.Instance);
|
||||
|
||||
// configure the container for web
|
||||
composition.ConfigureForWeb();
|
||||
|
||||
|
||||
composition.RegisterUnique<Dashboards>();
|
||||
|
||||
composition
|
||||
.ComposeUmbracoControllers(GetType().Assembly)
|
||||
.SetDefaultRenderMvcController<RenderMvcController>(); // default controller for template views
|
||||
@@ -202,6 +203,25 @@ namespace Umbraco.Web.Runtime
|
||||
.Append<MembersBackOfficeSection>()
|
||||
.Append<TranslationBackOfficeSection>();
|
||||
|
||||
|
||||
// register core CMS dashboards as types - will be ordered by weight attribute & merged with package.manifest dashboards
|
||||
// TODO WB Maybe use typeloader?!
|
||||
|
||||
composition.WithCollectionBuilder<DashboardCollectionBuilder>()
|
||||
.Add(composition.TypeLoader.GetTypes<IDashboardSection>());
|
||||
|
||||
//.Add<ContentDashboard>()
|
||||
//.Add<RedirectUrlDashboard>()
|
||||
//.Add<MediaDashboard>()
|
||||
//.Add<SettingsDashboard>()
|
||||
//.Add<ExamineDashboard>()
|
||||
//.Add<PublishedStatusDashboard>()
|
||||
//.Add<ModelsBuilderDashboard>()
|
||||
//.Add<HealthCheckDashboard>()
|
||||
//.Add<MembersDashboard>()
|
||||
//.Add<FormsDashboard>();
|
||||
|
||||
|
||||
// register back office trees
|
||||
foreach (var treeControllerType in umbracoApiControllerTypes
|
||||
.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x)))
|
||||
|
||||
@@ -1,65 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Services;
|
||||
using Umbraco.Web.Dashboards;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
namespace Umbraco.Web.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class for determine dashboard security
|
||||
/// </summary>
|
||||
internal class DashboardSecurity
|
||||
internal class DashboardService : IDashboardService
|
||||
{
|
||||
//TODO: Unit test all this!!! :/
|
||||
private readonly ISectionService _sectionService;
|
||||
private readonly DashboardCollection _dashboardCollection;
|
||||
|
||||
public static bool AuthorizeAccess(ISection dashboardSection, IUser user, ISectionService sectionService)
|
||||
public DashboardService(ISectionService sectionService, DashboardCollection dashboardCollection)
|
||||
{
|
||||
return CheckUserAccessByRules(user, sectionService, dashboardSection.AccessRights.Rules);
|
||||
_sectionService = sectionService ?? throw new ArgumentNullException(nameof(sectionService));
|
||||
_dashboardCollection = dashboardCollection ?? throw new ArgumentNullException(nameof(dashboardCollection));
|
||||
}
|
||||
|
||||
public static bool AuthorizeAccess(IDashboardTab dashboardTab, IUser user, ISectionService sectionService)
|
||||
{
|
||||
return CheckUserAccessByRules(user, sectionService, dashboardTab.AccessRights.Rules);
|
||||
}
|
||||
|
||||
public static bool AuthorizeAccess(IDashboardControl dashboardControl, IUser user, ISectionService sectionService)
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Tab<IDashboardSection>> GetDashboards(string section, IUser currentUser)
|
||||
{
|
||||
return CheckUserAccessByRules(user, sectionService, dashboardControl.AccessRights.Rules);
|
||||
}
|
||||
var tabs = new List<Tab<IDashboardSection>>();
|
||||
var tabId = 0;
|
||||
|
||||
private static (IAccessRule[], IAccessRule[], IAccessRule[]) GroupRules(IEnumerable<IAccessRule> rules)
|
||||
{
|
||||
IAccessRule[] denyRules = null, grantRules = null, grantBySectionRules = null;
|
||||
|
||||
var groupedRules = rules.GroupBy(x => x.Type);
|
||||
foreach (var group in groupedRules)
|
||||
foreach (var dashboard in _dashboardCollection.Where(x => x.Sections.InvariantContains(section)))
|
||||
{
|
||||
var a = group.ToArray();
|
||||
switch (group.Key)
|
||||
// validate access
|
||||
if (!CheckUserAccessByRules(currentUser, _sectionService, dashboard.AccessRules))
|
||||
continue;
|
||||
|
||||
if (dashboard.View.InvariantEndsWith(".ascx"))
|
||||
throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported.");
|
||||
|
||||
var dashboards = new List<IDashboardSection>();
|
||||
dashboards.Add(dashboard);
|
||||
|
||||
tabs.Add(new Tab<IDashboardSection>()
|
||||
{
|
||||
case AccessRuleType.Deny:
|
||||
denyRules = a;
|
||||
break;
|
||||
case AccessRuleType.Grant:
|
||||
grantRules = a;
|
||||
break;
|
||||
case AccessRuleType.GrantBySection:
|
||||
grantBySectionRules = a;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("panic");
|
||||
}
|
||||
Id = tabId++,
|
||||
Label = dashboard.Name,
|
||||
Alias = dashboard.Alias,
|
||||
Properties = dashboards
|
||||
});
|
||||
}
|
||||
|
||||
return (denyRules ?? Array.Empty<IAccessRule>(), grantRules ?? Array.Empty<IAccessRule>(), grantBySectionRules ?? Array.Empty<IAccessRule>());
|
||||
return tabs;
|
||||
}
|
||||
|
||||
public static bool CheckUserAccessByRules(IUser user, ISectionService sectionService, IEnumerable<IAccessRule> rules)
|
||||
/// <inheritdoc />
|
||||
public IDictionary<string, IEnumerable<Tab<IDashboardSection>>> GetDashboards(IUser currentUser)
|
||||
{
|
||||
return _sectionService.GetSections().ToDictionary(x => x.Alias, x => GetDashboards(x.Alias, currentUser));
|
||||
}
|
||||
|
||||
private bool CheckUserAccessByRules(IUser user, ISectionService sectionService, IEnumerable<IAccessRule> rules)
|
||||
{
|
||||
if (user.Id == Constants.Security.SuperUserId)
|
||||
return true;
|
||||
@@ -111,5 +109,32 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
return hasAccess;
|
||||
}
|
||||
|
||||
private (IAccessRule[], IAccessRule[], IAccessRule[]) GroupRules(IEnumerable<IAccessRule> rules)
|
||||
{
|
||||
IAccessRule[] denyRules = null, grantRules = null, grantBySectionRules = null;
|
||||
|
||||
var groupedRules = rules.GroupBy(x => x.Type);
|
||||
foreach (var group in groupedRules)
|
||||
{
|
||||
var a = group.ToArray();
|
||||
switch (group.Key)
|
||||
{
|
||||
case AccessRuleType.Deny:
|
||||
denyRules = a;
|
||||
break;
|
||||
case AccessRuleType.Grant:
|
||||
grantRules = a;
|
||||
break;
|
||||
case AccessRuleType.GrantBySection:
|
||||
grantBySectionRules = a;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("panic");
|
||||
}
|
||||
}
|
||||
|
||||
return (denyRules ?? Array.Empty<IAccessRule>(), grantRules ?? Array.Empty<IAccessRule>(), grantBySectionRules ?? Array.Empty<IAccessRule>());
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/Umbraco.Web/Services/IDashboardService.cs
Normal file
27
src/Umbraco.Web/Services/IDashboardService.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Services
|
||||
{
|
||||
public interface IDashboardService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets dashboard for a specific section/application
|
||||
/// For a specific backoffice user
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <param name="currentUser"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Tab<IDashboardSection>> GetDashboards(string section, IUser currentUser);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all dashboards, organized by section, for a user.
|
||||
/// </summary>
|
||||
/// <param name="currentUser"></param>
|
||||
/// <returns></returns>
|
||||
IDictionary<string, IEnumerable<Tab<IDashboardSection>>> GetDashboards(IUser currentUser);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,18 @@
|
||||
<Compile Include="Composing\LightInject\LightInjectContainer.cs" />
|
||||
<Compile Include="Components\BackOfficeUserAuditEventsComponent.cs" />
|
||||
<Compile Include="ContentApps\ListViewContentAppFactory.cs" />
|
||||
<Compile Include="Dashboards\ContentDashboard.cs" />
|
||||
<Compile Include="Dashboards\DashboardCollection.cs" />
|
||||
<Compile Include="Dashboards\DashboardCollectionBuilder.cs" />
|
||||
<Compile Include="Dashboards\ExamineDashboard.cs" />
|
||||
<Compile Include="Dashboards\FormsDashboard.cs" />
|
||||
<Compile Include="Dashboards\HealthCheckDashboard.cs" />
|
||||
<Compile Include="Dashboards\MediaDashboard.cs" />
|
||||
<Compile Include="Dashboards\MembersDashboard.cs" />
|
||||
<Compile Include="Dashboards\ModelsBuilderDashboard.cs" />
|
||||
<Compile Include="Dashboards\PublishedStatusDashboard.cs" />
|
||||
<Compile Include="Dashboards\RedirectUrlDashboard.cs" />
|
||||
<Compile Include="Dashboards\SettingsDashboards.cs" />
|
||||
<Compile Include="Editors\BackOfficePreviewModel.cs" />
|
||||
<Compile Include="Editors\PackageController.cs" />
|
||||
<Compile Include="Editors\KeepAliveController.cs" />
|
||||
@@ -169,6 +181,8 @@
|
||||
<Compile Include="Media\UploadAutoFillProperties.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
|
||||
<Compile Include="Services\DashboardService.cs" />
|
||||
<Compile Include="Services\IDashboardService.cs" />
|
||||
<Compile Include="Trees\BackOfficeSectionCollectionBuilder.cs" />
|
||||
<Compile Include="Trees\MediaBackOfficeSection.cs" />
|
||||
<Compile Include="Trees\MembersBackOfficeSection.cs" />
|
||||
@@ -244,7 +258,6 @@
|
||||
<Compile Include="WebApi\SerializeVersionAttribute.cs" />
|
||||
<Compile Include="WebApi\TrimModelBinder.cs" />
|
||||
<Compile Include="Editors\CodeFileController.cs" />
|
||||
<Compile Include="Editors\Dashboards.cs" />
|
||||
<Compile Include="Editors\DictionaryController.cs" />
|
||||
<Compile Include="Editors\EditorModelEventArgs.cs" />
|
||||
<Compile Include="Editors\EditorValidatorCollection.cs" />
|
||||
@@ -705,7 +718,6 @@
|
||||
<Compile Include="Editors\Filters\ContentSaveValidationAttribute.cs" />
|
||||
<Compile Include="Editors\ContentTypeControllerBase.cs" />
|
||||
<Compile Include="Editors\DashboardController.cs" />
|
||||
<Compile Include="Editors\DashboardSecurity.cs" />
|
||||
<Compile Include="Editors\DataTypeController.cs" />
|
||||
<Compile Include="Editors\DataTypeValidateAttribute.cs" />
|
||||
<Compile Include="Editors\ImagesController.cs" />
|
||||
@@ -826,7 +838,6 @@
|
||||
<Compile Include="Editors\EntityController.cs" />
|
||||
<Compile Include="Editors\MemberController.cs" />
|
||||
<Compile Include="Editors\CurrentUserController.cs" />
|
||||
<Compile Include="Models\ContentEditing\DashboardControl.cs" />
|
||||
<Compile Include="Models\ContentEditing\DataTypeDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\DataTypeSave.cs" />
|
||||
<Compile Include="Models\ContentEditing\DataTypeConfigurationFieldDisplay.cs" />
|
||||
|
||||
Reference in New Issue
Block a user