diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index ba104df97d..0e45a24adb 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -61,10 +61,89 @@ namespace Umbraco.Tests.Models.Mapping { //initialize our content type mapper var mapper = new ContentTypeModelMapper(new Lazy(() => _propertyEditorResolver.Object)); - mapper.ConfigureMappings(configuration, appContext); + mapper.ConfigureMappings(configuration, appContext); + var entityMapper = new EntityModelMapper(); + entityMapper.ConfigureMappings(configuration, appContext); }); } + [Test] + public void ContentTypeDisplay_To_PropertyType() + { + // setup the mocks to return the data we want to test against... + + _dataTypeService.Setup(x => x.GetDataTypeDefinitionById(It.IsAny())) + .Returns(Mock.Of( + definition => + definition.Id == 555 + && definition.PropertyEditorAlias == "myPropertyType" + && definition.DatabaseType == DataTypeDatabaseType.Nvarchar)); + + var display = new PropertyTypeDisplay() + { + Id = 1, + Alias = "test", + ContentTypeId = 4, + Description = "testing", + DataTypeId = 555, + + Value = "testsdfasdf", + Inherited = false, + Editor = "blah", + SortOrder = 6, + ContentTypeName = "Hello", + Label = "asdfasdf", + GroupId = 8, + Validation = new PropertyTypeValidation() + { + Mandatory = true, + Pattern = "asdfasdfa" + } + }; + + var result = Mapper.Map(display); + + Assert.AreEqual(1, result.Id); + Assert.AreEqual("test", result.Alias); + Assert.AreEqual("testing", result.Description); + Assert.AreEqual("blah", result.PropertyEditorAlias); + Assert.AreEqual(6, result.SortOrder); + Assert.AreEqual("asdfasdf", result.Name); + Assert.AreEqual(8, result.PropertyGroupId.Value); + + } + + [Test] + public void ContentGroupDisplay_To_PropertyGroup() + { + var display = new PropertyGroupDisplay() + { + ContentTypeId = 2, + Id = 1, + Inherited = false, + Name = "test", + ParentGroupId = 4, + ParentTabContentTypeNames = new[] + { + "hello", "world" + }, + SortOrder = 5, + ParentTabContentTypes = new[] + { + 10, 11 + } + }; + + + var result = Mapper.Map(display); + + Assert.AreEqual(1, result.Id); + Assert.AreEqual("test", result.Name); + Assert.AreEqual(4, result.ParentId); + Assert.AreEqual(5, result.SortOrder); + + } + [Test] public void ContentTypeDisplay_To_IContentType() { @@ -97,10 +176,12 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(display.Path, result.Path); Assert.AreEqual(display.Thumbnail, result.Thumbnail); Assert.AreEqual(display.IsContainer, result.IsContainer); + Assert.AreEqual(display.AllowAsRoot, result.AllowedAsRoot); //TODO: Now we need to assert all of the more complicated parts Assert.AreEqual(1, result.PropertyGroups.Count); Assert.AreEqual(1, result.PropertyGroups[0].PropertyTypes.Count); + Assert.AreEqual(display.AllowedTemplates.Count(), result.AllowedTemplates.Count()); } [Test] @@ -123,6 +204,17 @@ namespace Umbraco.Tests.Models.Mapping .Returns(new[] { new TextboxPropertyEditor() }); var contentType = MockedContentTypes.CreateTextpageContentType(); + //ensure everything has ids + contentType.Id = 1234; + var itemid = 8888; + foreach (var propertyGroup in contentType.CompositionPropertyGroups) + { + propertyGroup.Id = itemid++; + } + foreach (var propertyType in contentType.CompositionPropertyTypes) + { + propertyType.Id = itemid++; + } //Act @@ -152,7 +244,8 @@ namespace Umbraco.Tests.Models.Mapping { return new ContentTypeDisplay { - Alias = "test", + Alias = "test", + AllowAsRoot = true, AllowedTemplates = new List(), AvailableCompositeContentTypes = new List(), DefaultTemplate = new EntityBasic(){ Alias = "test" }, @@ -165,15 +258,15 @@ namespace Umbraco.Tests.Models.Mapping ParentId = -1, Thumbnail = "tree-thumb", IsContainer = true, - Groups = new List() + Groups = new List() { - new PropertyTypeGroupDisplay + new PropertyGroupDisplay { Id = 987, Name = "Tab 1", ParentGroupId = -1, SortOrder = 0, - Inherited = false, + Inherited = false, Properties = new List { new PropertyTypeDisplay diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js index 6405457e49..c48e06aea5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js @@ -1,15 +1,38 @@ angular.module("umbraco.directives.html") -.directive('umbEditorHeader', function () { - return { - transclude: true, - restrict: 'E', - replace: true, - scope: { - tabs: "=", - actions: "=", - name: "=", - menu: "=" - }, - templateUrl: 'views/components/editor/umb-editor-header.html' - }; -}); \ No newline at end of file + .directive('umbEditorHeader', function (iconHelper) { + return { + transclude: true, + restrict: 'E', + replace: true, + scope: { + tabs: "=", + actions: "=", + name: "=", + menu: "=", + icon: "=", + alias: "=", + description: "=", + navigation: "=" + }, + templateUrl: 'views/components/editor/umb-editor-header.html', + link: function(scope, elem, attrs, ctrl) { + + scope.pickIcon = function() { + + scope.dialogModel = {}; + scope.dialogModel.title = "Choose icon"; + scope.dialogModel.view = "views/common/dialogs/iconpicker.html"; + scope.showDialog = true; + + /* + iconHelper.getIcons().then(function(icons){ + scope.icons = icons; + }); + */ + + }; + + + } + }; + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js new file mode 100644 index 0000000000..aedb754f3d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js @@ -0,0 +1,40 @@ +angular.module("umbraco.directives") + .directive('umbEditorNavigation', function () { + return { + scope: { + navigation: "=" + }, + restrict: 'E', + replace: true, + templateUrl: 'views/components/editor/umb-editor-navigation.html', + link: function (scope, element, attrs, ctrl) { + + scope.clickNavigationItem = function(selectedItem) { + setItemToActive(selectedItem); + runItemAction(selectedItem); + }; + + function runItemAction(selectedItem) { + if(selectedItem.action) { + selectedItem.action(selectedItem); + } + } + + function setItemToActive(selectedItem) { + // set all other views to inactive + if(selectedItem.view) { + + for (var index = 0; index < scope.navigation.length; index++) { + var item = scope.navigation[index]; + item.active = false; + } + + // set view to active + selectedItem.active = true; + + } + } + + } + }; + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorsubviews.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorsubviews.directive.js new file mode 100644 index 0000000000..1ddb089632 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorsubviews.directive.js @@ -0,0 +1,40 @@ +angular.module("umbraco.directives") + .directive('umbEditorSubViews', function () { + return { + restrict: 'E', + replace: true, + templateUrl: 'views/components/editor/umb-editor-sub-views.html', + link: function (scope, element, attrs, ctrl) { + + scope.tools = []; + scope.activeView = {}; + + // set toolbar from selected navigation item + function setToolBar(items) { + + scope.tools = []; + + for (var index = 0; index < items.length; index++) { + var item = items[index]; + + if(item.active && item.tools) { + scope.tools = item.tools; + } + + if(item.active && item.view) { + scope.activeView = item; + } + } + } + + // watch for navigation changes + scope.$watch('page.navigation', function(newValue, oldValue) { + if (newValue) { + + setToolBar(newValue); + } + },true); + + } + }; + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index 557af547e6..5055da2d7c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -90,6 +90,8 @@ @import "components/overlays.less"; @import "components/card.less"; @import "components/umb-sub-views"; +@import "components/umb-editor-navigation"; +@import "components/umb-editor-sub-views"; //page specific styles 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 new file mode 100644 index 0000000000..96222b58fa --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -0,0 +1,25 @@ +.umb-sub-views-nav { + list-style: none; + display: flex; + margin: 0; +} + +.umb-sub-views-nav-item { + text-align: center; + margin-left: 20px; + cursor: pointer; +} + +.umb-sub-views-nav-item.is-active { + color: @blue; +} + +.umb-sub-views-nav-item .icon { + font-size: 24px; + display: block; + text-align: center; +} + +.umb-sub-views-nav-item-text { + font-size: 11px; +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-sub-views.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-sub-views.less new file mode 100644 index 0000000000..33c0161311 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-sub-views.less @@ -0,0 +1,33 @@ +/* --------- COLUMNS --------- */ + +.sub-view-columns { + display: flex; + margin-bottom: 40px; +} + +.sub-view-columns h5 { + margin-top: 0; +} + +.sub-view-column-left { + flex: 0 0 250px; + margin-right: 70px; +} + +.sub-view-column-right { + flex: 1; +} + +/* ---------- TOOLS ---------- */ + +.umb-editor-sub-views-tools { + display: flex; + justify-content: flex-end; + margin-bottom: 20px; + height: 25px; +} + +.umb-editor-sub-views-tool { + margin-left: 20px; + cursor: pointer; +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/pages/document-type-editor.less b/src/Umbraco.Web.UI.Client/src/less/pages/document-type-editor.less index b729c99665..7c9302de4b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/pages/document-type-editor.less +++ b/src/Umbraco.Web.UI.Client/src/less/pages/document-type-editor.less @@ -42,10 +42,6 @@ /* ---------- TABS ---------- */ - .content-type-groups-list { - margin-top: 90px; // compensate for tab-title position absolute - } - .edt-tab{ margin: 50px 0 0 0; min-height: 145px; diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less index 9b0400e7c6..a45e410d3c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/panel.less @@ -292,6 +292,19 @@ /* --------- UMB PANEL HEADER ---------- */ +.umb-panel-content { + display: flex; + align-items: center; + height: 100px; + padding: 0 20px; + justify-content: space-between; +} + +.umb-panel-meta { + display: flex; + align-items: center; +} + // icon .umb-panel-header-icon { width: 50px; @@ -299,27 +312,55 @@ background: #ffffff; border: 1px dashed @gray; border-radius: 5px; - float: left; text-align: center; font-size: 11px; line-height: 50px; cursor: pointer; - margin-left: 15px; - margin-top: 15px; + margin: 0 5px 0 0; opacity: 0.7; } .umb-panel-header-title-wrapper { - float: left; - width: 400px; + +} + +.umb-panel-header-name-wrapper { + display: flex; + align-items: center; +} + +input.umb-panel-header-name { + border: 1px solid transparent; + background: transparent; + font-size: 16px; + color: #000000; + margin: 0 5px 0 0; + max-height: 25px; + &:hover { + background: #ffffff; + border: 1px solid #cccccc; + } } .umb-panel-header-alias { - margin-top: 5px; - margin-left: 20px; font-size: 13px; color: #cccccc; + cursor: pointer; .icon { margin-right: 5px; } } + +input.umb-panel-header-description { + background: transparent; + border-color: transparent; + width: 35%; + min-width: 300px; + margin: -5px 0 0 0; + &:hover { + background: #ffffff; + border-color: #cccccc; + } +} + + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html index 5509263554..d11182e07b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html @@ -1,39 +1,42 @@ 
-
-
+ +
+ +
+
Add icon
+
+ -
- - Actions - - +
+ +
{{ alias }}
+ +
-
+ +
+ + + +
+ + +
-
\ 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 new file mode 100644 index 0000000000..1f0ba0ba90 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -0,0 +1,6 @@ +
    +
  • + + {{ item.name }} +
  • +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-sub-views.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-sub-views.html new file mode 100644 index 0000000000..a25918474b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-sub-views.html @@ -0,0 +1,13 @@ +
+ +
+
+ {{ tool.name }} +
+
+ +
+
+ +
+ diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.controller.js index d32634d2f8..037042da0d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.controller.js @@ -11,45 +11,43 @@ function DocumentTypeEditController($scope, $rootScope, $routeParams, $log, cont $scope.page = {actions: [], menu: [], subViews: [] }; $scope.sortingMode = false; - $scope.page.subViews = [ + $scope.page.navigation = [ { "name": "Design", "icon": "merge", "view": "views/documentType/views/design/design.html", + "active": true, "tools": [ - { - "name": "Compositions", - "icon": "merge", - "action": function() { - $scope.openCompositionsDialog(); - } - }, - { - "name": "Reorder", - "icon": "navigation", - "action": function() { - $scope.toggleSortingMode(); - } + { + "name": "Compositions", + "icon": "merge", + "action": function() { + $scope.openCompositionsDialog(); } - ] + }, + { + "name": "Reorder", + "icon": "navigation", + "action": function() { + $scope.toggleSortingMode(); + } + } + ] }, { "name": "List view", "icon": "list", - "view": "views/documentType/views/listview/listview.html", - "tools": [] + "view": "views/documentType/views/listview/listview.html" }, { "name": "Permissions", "icon": "keychain", - "view": "views/documentType/views/permissions/permissions.html", - "tools": [] + "view": "views/documentType/views/permissions/permissions.html" }, { "name": "Templates", "icon": "article", - "view": "views/documentType/views/templates/templates.html", - "tools": [] + "view": "views/documentType/views/templates/templates.html" } ]; diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.html b/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.html index 25b2e5db3e..af436db6ac 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttype/edit.html @@ -9,17 +9,21 @@ name="contentType.name" alias="contentType.alias" description="contentType.description" - menu="page.menu" - actions="page.menu"> + navigation="page.navigation">
- + +
diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 84d62322d2..fcc767a2f4 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -59,7 +59,7 @@ namespace Umbraco.Web.Editors } - public Umbraco.Web.Models.ContentEditing.ContentTypeDisplay GetById(int id) + public ContentTypeDisplay GetById(int id) { var ct = Services.ContentTypeService.GetContentType(id); if (ct == null) @@ -67,14 +67,14 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var dto = Mapper.Map(ct); + var dto = Mapper.Map(ct); return dto; } - public Umbraco.Web.Models.ContentEditing.ContentTypeDisplay GetEmpty() + public ContentTypeDisplay GetEmpty() { var ct = new ContentType(-1); - var dto = Mapper.Map(ct); + var dto = Mapper.Map(ct); return dto; } @@ -102,18 +102,17 @@ namespace Umbraco.Web.Editors /// /// Returns all content type objects /// - /// public IEnumerable GetAll() { var types = Services.ContentTypeService.GetAllContentTypes(); var basics = types.Select(Mapper.Map); - foreach (var basic in basics) + + return basics.Select(basic => { basic.Name = TranslateItem(basic.Name); basic.Description = TranslateItem(basic.Description); - } - - return basics; + return basic; + }); } /// @@ -166,10 +165,10 @@ namespace Umbraco.Web.Editors var ctService = ApplicationContext.Services.ContentTypeService; - ///TODO: warn on content type alias conflicts - ///TODO: warn on property alias conflicts + //TODO: warn on content type alias conflicts + //TODO: warn on property alias conflicts - ///TODO: Validate the submitted model + //TODO: Validate the submitted model var ctId = Convert.ToInt32(contentType.Id); @@ -196,8 +195,7 @@ namespace Umbraco.Web.Editors contentType.Id = null; //save as new - IContentType newCt = new ContentType(-1); - Mapper.Map(contentType, newCt); + var newCt = Mapper.Map(contentType); ctService.Save(newCt); diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs index ea7202ac69..57099272a5 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs @@ -17,7 +17,7 @@ namespace Umbraco.Web.Models.ContentEditing AvailableCompositeContentTypes = new List(); AllowedContentTypes = new List(); CompositeContentTypes = new List(); - Groups = new List(); + Groups = new List(); } //name, alias, icon, thumb, desc, inherited from basic @@ -55,6 +55,6 @@ namespace Umbraco.Web.Models.ContentEditing //Tabs [DataMember(Name = "groups")] - public IEnumerable Groups { get; set; } + public IEnumerable Groups { get; set; } } } diff --git a/src/Umbraco.Web/Models/ContentEditing/MemberTypeDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MemberTypeDisplay.cs index a50f511d4d..225022b653 100644 --- a/src/Umbraco.Web/Models/ContentEditing/MemberTypeDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/MemberTypeDisplay.cs @@ -13,13 +13,13 @@ namespace Umbraco.Web.Models.ContentEditing public MemberTypeDisplay() { //initialize collections so at least their never null - Groups = new List(); + Groups = new List(); } //name, alias, icon, thumb, desc, inherited from basic //Tabs [DataMember(Name = "groups")] - public IEnumerable Groups { get; set; } + public IEnumerable Groups { get; set; } } } diff --git a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeGroupDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/PropertyGroupDisplay.cs similarity index 89% rename from src/Umbraco.Web/Models/ContentEditing/PropertyTypeGroupDisplay.cs rename to src/Umbraco.Web/Models/ContentEditing/PropertyGroupDisplay.cs index 2dfc94d10c..85ee636b9a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeGroupDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/PropertyGroupDisplay.cs @@ -7,10 +7,10 @@ using System.Threading.Tasks; namespace Umbraco.Web.Models.ContentEditing { - [DataContract(Name = "propertyTypeGroup", Namespace = "")] - public class PropertyTypeGroupDisplay + [DataContract(Name = "propertyGroup", Namespace = "")] + public class PropertyGroupDisplay { - public PropertyTypeGroupDisplay() + public PropertyGroupDisplay() { Properties = new List(); } diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs index 702e30fc0c..ad26dd8014 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs @@ -1,6 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; - +using System.Threading; using AutoMapper; using Umbraco.Core; using Umbraco.Core.Models; @@ -41,13 +42,13 @@ namespace Umbraco.Web.Models.Mapping //only map id if set to something higher then zero .ForMember(dto => dto.Id, expression => expression.Condition(display => (Convert.ToInt32(display.Id) > 0))) - + .ForMember(dto => dto.Id, expression => expression.MapFrom(display => Convert.ToInt32(display.Id))) + .ForMember(dto => dto.AllowedAsRoot, expression => expression.MapFrom(display => display.AllowAsRoot)) .ForMember(dto => dto.CreatorId, expression => expression.Ignore()) .ForMember(dto => dto.Level, expression => expression.Ignore()) .ForMember(dto => dto.CreateDate, expression => expression.Ignore()) .ForMember(dto => dto.UpdateDate, expression => expression.Ignore()) .ForMember(dto => dto.SortOrder, expression => expression.Ignore()) - //mapped in aftermap .ForMember(dto => dto.AllowedContentTypes, expression => expression.Ignore()) @@ -56,50 +57,57 @@ namespace Umbraco.Web.Models.Mapping .AfterMap((source, dest) => { dest.PropertyGroups = new PropertyGroupCollection(); - foreach (var groupDisplay in source.Groups.Where(x => !x.Name.IsNullOrWhiteSpace() ) ) + foreach (var groupDisplay in source.Groups.Where(x => x.Name.IsNullOrWhiteSpace() == false ) ) { dest.PropertyGroups.Add(Mapper.Map(groupDisplay)); } //Sync allowed child types - var allowedTypes = new List(); - var proposedAllowed = source.AllowedContentTypes.ToArray(); - for (int i = 0; i < proposedAllowed.Length; i++) - allowedTypes.Add(new ContentTypeSort(proposedAllowed[i], i)); + var allowedTypes = source.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i)); dest.AllowedContentTypes = allowedTypes; //sync compositions - var current = dest.CompositionAliases(); + var current = dest.CompositionAliases().ToArray(); var proposed = source.CompositeContentTypes; - var remove = current.Where(x => !proposed.Contains(x)); - var add = proposed.Where(x => !current.Contains(x)); + var remove = current.Where(x => proposed.Contains(x) == false); + var add = proposed.Where(x => current.Contains(x) == false); - foreach(var rem in remove) + foreach (var rem in remove) + { dest.RemoveContentType(rem); + } - foreach(var a in add){ - var add_ct = applicationContext.Services.ContentTypeService.GetContentType(a); - if(add_ct != null) - dest.AddContentType(add_ct); + foreach(var a in add) + { + //TODO: Remove N+1 lookup + var addCt = applicationContext.Services.ContentTypeService.GetContentType(a); + if(addCt != null) + dest.AddContentType(addCt); } }); config.CreateMap().ConvertUsing(x => x.Id.Value); config.CreateMap().ConvertUsing(x => x.Alias); + config.CreateMap() + .ForMember(display => display.AllowAsRoot, expression => expression.MapFrom(type => type.AllowedAsRoot)) //Ignore because this is not actually used for content types .ForMember(display => display.Trashed, expression => expression.Ignore()) + .ForMember( + dto => dto.AllowedContentTypes, + expression => expression.MapFrom(dto => dto.AllowedContentTypes.Select(x => x.Id.Value))) + .ForMember( dto => dto.AvailableCompositeContentTypes, expression => expression.ResolveUsing(new AvailableCompositeContentTypesResolver(applicationContext))) .ForMember( dto => dto.CompositeContentTypes, - expression => expression.MapFrom(dto => dto.ContentTypeComposition) ) + expression => expression.MapFrom(dto => dto.ContentTypeComposition)) .ForMember( dto => dto.CompositeContentTypes, @@ -109,10 +117,12 @@ namespace Umbraco.Web.Models.Mapping dto => dto.Groups, expression => expression.ResolveUsing(new PropertyTypeGroupResolver(applicationContext, _propertyEditorResolver))); - - config.CreateMap() + config.CreateMap() .ForMember(dest => dest.Id, expression => expression.Condition(source => source.Id > 0)) - .ForMember(g => g.CreateDate, expression => expression.Ignore()) + .ForMember(g => g.CreateDate, expression => expression.Ignore()) + .ForMember(g => g.Key, expression => expression.Ignore()) + .ForMember(g => g.CreateDate, expression => expression.Ignore()) + .ForMember(g => g.HasIdentity, expression => expression.Ignore()) .ForMember(g => g.UpdateDate, expression => expression.Ignore()) //only map if a parent is actually set @@ -123,6 +133,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(g => g.PropertyTypes, expression => expression.Ignore()) .AfterMap((source, destination) => { + + destination.PropertyTypes = new PropertyTypeCollection(); foreach (var propertyTypeDisplay in source.Properties.Where(x => x.Label.IsNullOrWhiteSpace() == false )) { @@ -138,6 +150,10 @@ namespace Umbraco.Web.Models.Mapping if (dataType == null) throw new NullReferenceException("No data type found with id " + propertyTypeDisplay.DataTypeId); return new PropertyType(dataType, propertyTypeDisplay.Alias); }) + .ForMember(type => type.PropertyGroupId, expression => expression.MapFrom(display => new Lazy(() => display.GroupId, LazyThreadSafetyMode.None))) + .ForMember(type => type.Key, expression => expression.Ignore()) + .ForMember(type => type.HelpText, expression => expression.Ignore()) + .ForMember(type => type.HasIdentity, expression => expression.Ignore()) //ignore because this is set in the ctor .ForMember(type => type.Alias, expression => expression.Ignore()) //ignore because this is obsolete and shouldn't be used diff --git a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs index 20fc9cdd6a..4d159c5abd 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs @@ -47,25 +47,34 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-layout")) - .ForMember(basic => basic.Path, expression => expression.UseValue("")) + .ForMember(basic => basic.Path, expression => expression.MapFrom(template => template.Path)) .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) .ForMember(dto => dto.Trashed, expression => expression.Ignore()) .ForMember(x => x.AdditionalData, expression => expression.Ignore()); + config.CreateMap() + .ConstructUsing(basic => new Template(basic.Name, basic.Alias) + { + Id = Convert.ToInt32(basic.Id), + Key = basic.Key + }) + .ForMember(t => t.Path, expression => expression.MapFrom(template => template.Path)) + .ForMember(t => t.Id, expression => expression.MapFrom(template => Convert.ToInt32(template.Id))) + .ForMember(x => x.VirtualPath, expression => expression.Ignore()) + .ForMember(x => x.CreateDate, expression => expression.Ignore()) + .ForMember(x => x.UpdateDate, expression => expression.Ignore()) + .ForMember(x => x.Content, expression => expression.Ignore()); + + config.CreateMap() + .ForMember(x => x.Id, expression => expression.MapFrom(entity => new Lazy(() => Convert.ToInt32(entity.Id)))) + .ForMember(x => x.SortOrder, expression => expression.Ignore()); + config.CreateMap() - .ForMember(basic => basic.Path, expression => expression.UseValue("")) - .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) - .ForMember(dto => dto.Trashed, expression => expression.Ignore()) - .ForMember(x => x.AdditionalData, expression => expression.Ignore()); - - config.CreateMap() - .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-grid")) - .ForMember(basic => basic.Path, expression => expression.UseValue("")) - .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) - .ForMember(dto => dto.Trashed, expression => expression.Ignore()) - .ForMember(x => x.AdditionalData, expression => expression.Ignore()); - - + .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-grid")) + .ForMember(basic => basic.Path, expression => expression.MapFrom(x => x.Path)) + .ForMember(basic => basic.ParentId, expression => expression.MapFrom(x => x.ParentId)) + .ForMember(dto => dto.Trashed, expression => expression.Ignore()) + .ForMember(x => x.AdditionalData, expression => expression.Ignore()); config.CreateMap() //default to document icon diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs index 027aaaf42b..cc26be9305 100644 --- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs @@ -11,8 +11,9 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Mapping { + - internal class PropertyTypeGroupResolver : ValueResolver> + internal class PropertyTypeGroupResolver : ValueResolver> { private readonly ApplicationContext _applicationContext; private readonly Lazy _propertyEditorResolver; @@ -24,9 +25,9 @@ namespace Umbraco.Web.Models.Mapping } - protected override IEnumerable ResolveCore(IContentTypeComposition source) + protected override IEnumerable ResolveCore(IContentTypeComposition source) { - var groups = new Dictionary(); + var groups = new Dictionary(); //for storing generic properties var genericProperties = new List(); @@ -37,7 +38,7 @@ namespace Umbraco.Web.Models.Mapping { //process each tab foreach(var tab in ct.CompositionPropertyGroups){ - var group = new PropertyTypeGroupDisplay() { Id = tab.Id, Inherited = true, Name = tab.Name, SortOrder = tab.SortOrder }; + var group = new PropertyGroupDisplay() { Id = tab.Id, Inherited = true, Name = tab.Name, SortOrder = tab.SortOrder }; group.ContentTypeId = ct.Id; group.ParentTabContentTypes = new[] { ct.Id }; group.ParentTabContentTypeNames = new[] { ct.Name }; @@ -60,7 +61,7 @@ namespace Umbraco.Web.Models.Mapping //pull from own groups foreach (var ownTab in source.CompositionPropertyGroups) { - PropertyTypeGroupDisplay group; + PropertyGroupDisplay group; //if already added if (groups.ContainsKey(ownTab.Id)) @@ -73,7 +74,7 @@ namespace Umbraco.Web.Models.Mapping else { //if own - group = new PropertyTypeGroupDisplay() { Id = ownTab.Id, Inherited = false, Name = ownTab.Name, SortOrder = ownTab.SortOrder, ContentTypeId = source.Id }; + group = new PropertyGroupDisplay() { Id = ownTab.Id, Inherited = false, Name = ownTab.Name, SortOrder = ownTab.SortOrder, ContentTypeId = source.Id }; groups.Add(ownTab.Id, group); } @@ -94,7 +95,7 @@ namespace Umbraco.Web.Models.Mapping if (genericProperties.Any()) { - var genericTab = new PropertyTypeGroupDisplay() { Id = 0, Name = "Generic properties", ParentGroupId = 0, ContentTypeId = source.Id, SortOrder = 999, Inherited = false }; + var genericTab = new PropertyGroupDisplay() { Id = 0, Name = "Generic properties", ParentGroupId = 0, ContentTypeId = source.Id, SortOrder = 999, Inherited = false }; groups.Add(0, genericTab); } @@ -103,7 +104,7 @@ namespace Umbraco.Web.Models.Mapping var nameGroupedGroups = groups.Values.GroupBy(x => x.Name); if (nameGroupedGroups.Any(x => x.Count() > 1)) { - var sortedGroups = new List(); + var sortedGroups = new List(); foreach (var groupOfGroups in nameGroupedGroups) { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3474a67382..4cedd9d5b7 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -307,7 +307,7 @@ - +