From 513caad41bbe9689a54cc6958b7823995bcbb634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gert=20S=C3=B8nderby?= Date: Tue, 23 Aug 2016 14:18:24 +0200 Subject: [PATCH 01/95] Added custom function to assert that a system browser tree node has no children, or does not have a particular child. --- Website/test/e2e/pageObjects/systemView.js | 9 +++++++++ Website/test/e2e/suite/400_content/browseTree.js | 2 ++ 2 files changed, 11 insertions(+) diff --git a/Website/test/e2e/pageObjects/systemView.js b/Website/test/e2e/pageObjects/systemView.js index dce3472951..fffae22e0f 100644 --- a/Website/test/e2e/pageObjects/systemView.js +++ b/Website/test/e2e/pageObjects/systemView.js @@ -33,6 +33,15 @@ module.exports = { this.expect .element(selector) .to.be.present; + }, + assertTreeNodeHasNoChild: function (parentLabel, childLabel) { + var selector = 'treenode[label="' + parentLabel + '"] > treenode'; + if (childLabel) { + selector += '[label="' + childLabel + '"]'; + } + this.expect + .element(selector) + .to.not.be.present; } }] }; diff --git a/Website/test/e2e/suite/400_content/browseTree.js b/Website/test/e2e/suite/400_content/browseTree.js index fac12604c3..fd609f6810 100644 --- a/Website/test/e2e/suite/400_content/browseTree.js +++ b/Website/test/e2e/suite/400_content/browseTree.js @@ -29,6 +29,8 @@ module.exports = { systemView.assertTreeNodeHasChild('Getting Started', 'Tests'); // 7 Select the “Tests” page The “Test” page gets selected in the tree. systemView.openTreeNode('Tests') + systemView.assertTreeNodeHasNoChild('Tests', 'Foo') + systemView.assertTreeNodeHasNoChild('Features') // The “Test” page’s content loads in the browser view. content .assertBrowserContains('div.content-column > h1', 'Test the design') From 9bb9d917e55b2b2e495981b908ae7105c2567695 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 29 Aug 2016 17:47:23 +0200 Subject: [PATCH 02/95] Refractor --- Composite/C1Console/Actions/AddNewTreeRefresher.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Composite/C1Console/Actions/AddNewTreeRefresher.cs b/Composite/C1Console/Actions/AddNewTreeRefresher.cs index 2715f6672d..3e2a6c6eb5 100644 --- a/Composite/C1Console/Actions/AddNewTreeRefresher.cs +++ b/Composite/C1Console/Actions/AddNewTreeRefresher.cs @@ -29,12 +29,19 @@ public AddNewTreeRefresher(EntityToken parentEntityToken, FlowControllerServices } - /// + [Obsolete("Use PostRefreshMessages instead")] public void PostRefreshMesseges(EntityToken newChildEntityToken) + { + PostRefreshMessages(newChildEntityToken); + } + + + /// + public void PostRefreshMessages(EntityToken newChildEntityToken) { Verify.ArgumentNotNull(newChildEntityToken, "newChildEntityToken"); - Verify.That(!_postRefreshMessegesCalled, "Only one PostRefreshMesseges call is allowed"); + Verify.That(!_postRefreshMessegesCalled, "Only one PostRefreshMessages call is allowed"); _postRefreshMessegesCalled = true; @@ -45,7 +52,8 @@ public void PostRefreshMesseges(EntityToken newChildEntityToken) foreach (EntityToken entityToken in RefreshBeforeAfterEntityTokenFinder.FindEntityTokens(_beforeGraph, _afterGraph)) { messageService.RefreshTreeSection(entityToken); - Log.LogVerbose("AddNewTreeRefresher", string.Format("Refreshing EntityToken: Type = {0}, Source = {1}, Id = {2}, EntityTokenType = {3}", entityToken.Type, entityToken.Source, entityToken.Id, entityToken.GetType())); + Log.LogVerbose("AddNewTreeRefresher", + $"Refreshing EntityToken: Type = {entityToken.Type}, Source = {entityToken.Source}, Id = {entityToken.Id}, EntityTokenType = {entityToken.GetType()}"); } } } From 50403f90535d63d048036526c82a9a12bcf588e0 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 29 Aug 2016 17:48:53 +0200 Subject: [PATCH 03/95] Adding duplicate action --- .../Actions/Data/ActionIdentifier.cs | 7 + .../C1Console/Actions/DuplicateActionToken.cs | 254 ++++++++++++++++++ .../Core/ResourceSystem/LocalizationFiles.cs | 42 ++- .../Composite.Management.en-us.xml | 4 + 4 files changed, 294 insertions(+), 13 deletions(-) create mode 100644 Composite/C1Console/Actions/DuplicateActionToken.cs diff --git a/Composite/C1Console/Actions/Data/ActionIdentifier.cs b/Composite/C1Console/Actions/Data/ActionIdentifier.cs index cb8ac91bd2..f6e6e75a9f 100644 --- a/Composite/C1Console/Actions/Data/ActionIdentifier.cs +++ b/Composite/C1Console/Actions/Data/ActionIdentifier.cs @@ -45,6 +45,9 @@ private ActionIdentifier(string identifier) /// public static ActionIdentifier Undo => new ActionIdentifier("Undo"); + /// + public static ActionIdentifier Duplicate => new ActionIdentifier("Duplicate"); + /// public IEnumerable Permissions() { @@ -86,6 +89,10 @@ public IEnumerable Permissions() { yield return PermissionType.Edit; } + if (this == Duplicate) + { + yield return PermissionType.Add; + } } /// diff --git a/Composite/C1Console/Actions/DuplicateActionToken.cs b/Composite/C1Console/Actions/DuplicateActionToken.cs new file mode 100644 index 0000000000..634a558e17 --- /dev/null +++ b/Composite/C1Console/Actions/DuplicateActionToken.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text.RegularExpressions; +using Composite.C1Console.Elements.Plugins.ElementAttachingProvider; +using Composite.C1Console.Security; +using Composite.C1Console.Events; +using Composite.C1Console.Trees; +using Composite.C1Console.Users; +using Composite.Core.Extensions; +using Composite.Core.ResourceSystem; +using Composite.Core.Types; +using Composite.Data; +using Composite.Data.DynamicTypes.Foundation; +using Composite.Data.ProcessControlled; +using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; +using Composite.Data.Types; +using Composite.Plugins.Commands.ConsoleCommandHandlers; + +namespace Composite.C1Console.Actions +{ + [ActionExecutor(typeof(DuplicateActionExecuter))] + internal class DuplicateActionToken : ActionToken + { + public override IEnumerable PermissionTypes => new[] { PermissionType.Add }; + + /// + public static ActionToken Deserialize(string serializedData) + { + return new DuplicateActionToken(); + } + } + + internal class DuplicateActionExecuter : IActionExecutor + { + /// + public FlowToken Execute(EntityToken entityToken, ActionToken actionToken, FlowControllerServicesContainer flowControllerServicesContainer) + { + return Execute(EntityTokenSerializer.Serialize(entityToken), ActionTokenSerializer.Serialize(actionToken), actionToken, flowControllerServicesContainer); + } + + /// + public FlowToken Execute(string serializedEntityToken, string serializedActionToken, ActionToken actionToken, FlowControllerServicesContainer flowControllerServicesContainer) + { + var dataEntityToken = (DataEntityToken)EntityTokenSerializer.Deserialize(serializedEntityToken); + + var data = dataEntityToken.Data; + + Verify.IsNotNull(data, "Failed to get the data from an entity token"); + + using (new DataScope(DataScopeIdentifier.Administrated)) + { + var treeRefresher = new AddNewTreeRefresher(dataEntityToken,flowControllerServicesContainer); + + var newData = (IData)StaticReflection.GetGenericMethodInfo(() => CloneData((IData)null)) + .MakeGenericMethod(data.DataSourceId.InterfaceType).Invoke(this, new object[] { data }); + + var consoleId = flowControllerServicesContainer.GetService().CurrentConsoleId; + + ConsoleCommandHelper.SelectConsoleElement(consoleId, newData.GetDataEntityToken()); + + treeRefresher.PostRefreshMesseges(dataEntityToken); + } + + return null; + } + + private IData CloneData(T data) where T : class, IData + { + IData newdata = DataFacade.BuildNew(); + + var dataProperties = typeof(T).GetPropertiesRecursively(); + + foreach (var propertyInfo in dataProperties.Where(f => f.CanWrite)) + { + if (data.GetKeyProperties().Contains(propertyInfo) && propertyInfo.PropertyType == typeof(Guid)) + { + propertyInfo.SetValue(newdata, Guid.NewGuid()); + } + else + { + propertyInfo.SetValue(newdata, propertyInfo.GetValue(data)); + } + + } + + var page = data as IPage; + if (page != null) + { + if(!SetNewValue(page,newdata, dataProperties.First(p => p.Name == nameof(IPage.MenuTitle)))) + { + SetNewValue(page, newdata, dataProperties.First(p => p.Name == nameof(IPage.Title))); + } + + SetNewValue(page, newdata, dataProperties.First(p => p.Name == nameof(IPage.UrlTitle)), isUrl:true); + + PageInsertPosition.After(page.Id).CreatePageStructure(newdata as IPage, page.GetParentId()); + + } + else + { + var labelProperty = typeof(T).GetProperty( + DynamicTypeReflectionFacade.GetLabelPropertyName(typeof(T))); + + if (labelProperty != null && labelProperty.PropertyType == typeof(string)) + { + SetNewValue(data, newdata, labelProperty); + } + } + + if (newdata is IPublishControlled) + { + (newdata as IPublishControlled).PublicationStatus = GenericPublishProcessController.Draft; + } + if (newdata is ILocalizedControlled) + { + (newdata as ILocalizedControlled).SourceCultureName = UserSettings.ActiveLocaleCultureInfo.Name; + } + + newdata = DataFacade.AddNew(newdata); + + if (data is IPage) + { + CopyPageData(data as IPage, newdata as IPage); + } + + return newdata; + } + + private bool SetNewValue( IData sourceData, IData newData, PropertyInfo property + ,bool isUrl=false) where T : class, IData + { + var value = isUrl? (string)property.GetValue(sourceData): + GetStringWithoutCopyOf((string) property.GetValue(sourceData)); + + if (!isUrl && value.IsNullOrEmpty()) + return false; + for (var count = 1;; count++) + { + var str = GenerateCopyOfName(value, count,isUrl); + if (DataFacade.GetData().Any(GetLambda(property, str))) continue; + property.SetValue(newData, str); + break; + } + return true; + } + + private Expression> GetLambda(PropertyInfo labelProperty, string labelValue) + { + var p = Expression.Parameter(typeof(T)); + var propertry = Expression.Property(p, labelProperty.Name); + var body = Expression.Equal(propertry, Expression.Constant(labelValue)); + return Expression.Lambda>(body, p); + } + + private static string GetStringWithoutCopyOf(string source) + { + Regex regexInstance = new Regex(StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text").Replace("{count}", ".*")+ " "); + return regexInstance.Replace(source, ""); + + } + + private string GenerateCopyOfName(string source, int count,bool isUrl=false) + { + if (isUrl) + { + return string.Join("-", source, count.ToString()); + } + + Func copyText = i => StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text") + .Replace("{count}", i == 1 ? "" : $"({i})"); + return string.Format(copyText(count), source); + } + + internal void CopyPageData(IPage sourcePage, IPage newPage) + { + Guid sourcePageId = sourcePage.Id; + Guid newPageId = newPage.Id; + //Guid sourceVersionId = sourcePage.VersionId; + + var newPlaceholders = new List(); + var placeholders = + DataFacade.GetData(). + Where(ph => ph.PageId == sourcePageId) + // && ph.VersionId == sourceVersionId) + .ToList(); + + foreach (var placeholderContent in placeholders) + { + var newPlaceholder = DataFacade.BuildNew(); + + newPlaceholder.PageId = newPageId; + newPlaceholder.PlaceHolderId = placeholderContent.PlaceHolderId; + newPlaceholder.Content = placeholderContent.Content; + //newPlaceholder.VersionId = newVersionId; + + newPlaceholders.Add(newPlaceholder); + } + DataFacade.AddNew(newPlaceholders); + + var sourceMetaData = sourcePage.GetMetaData().Cast(); + //.Where(d => d.VersionId == sourceVersionId); + foreach (var metaDataItem in sourceMetaData) + { + var metaDataType = metaDataItem.DataSourceId.InterfaceType; + var typeDescriptor = DataMetaDataFacade.GetDataTypeDescriptor(metaDataType.GetImmutableTypeId()); + var definition = PageMetaDataFacade.GetMetaDataDefinition(sourcePageId, metaDataItem.GetTypeTitle()); + + var newDataItem = (IPageMetaData)DataFacade.BuildNew(metaDataType); + + var properties = metaDataType.GetPropertiesRecursively().ToDictionary(p => p.Name); + foreach (var field in typeDescriptor.Fields) + { + var propertyInfo = properties[field.Name]; + propertyInfo.SetValue(newDataItem, propertyInfo.GetValue(metaDataItem)); + } + + //newDataItem.VersionId = newVersionId; + newDataItem.Id = Guid.NewGuid(); + newDataItem.PageId = newPageId; + newDataItem.PublicationStatus = GenericPublishProcessController.Draft; + DataFacade.AddNew((IData)newDataItem); + + string title = newDataItem.GetTypeTitle(); + newPage.AddMetaDataDefinition(title, title, newDataItem.GetImmutableTypeId(), definition.MetaDataContainerId); + } + + List selectableTreeIds = TreeFacade.AllTrees.Where( + tree => tree.HasPossibleAttachmentPoints(sourcePage.GetDataEntityToken())) + .Where(tree => !tree.HasAttachmentPoints(newPage.GetDataEntityToken())) + .Select(tree => tree.TreeId).ToList(); + + foreach (var selectableTreeId in selectableTreeIds) + { + TreeFacade.AddPersistedAttachmentPoint(selectableTreeId, newPage.DataSourceId.InterfaceType, + newPage.DataSourceId.GetKeyValue()); + } + + foreach (var dataFolderType in sourcePage.GetDefinedFolderTypes()) + { + newPage.AddFolderDefinition(dataFolderType); + } + + + + } + } + + +} diff --git a/Composite/Core/ResourceSystem/LocalizationFiles.cs b/Composite/Core/ResourceSystem/LocalizationFiles.cs index fa64009cd3..20b44fa1c4 100644 --- a/Composite/Core/ResourceSystem/LocalizationFiles.cs +++ b/Composite/Core/ResourceSystem/LocalizationFiles.cs @@ -195,6 +195,8 @@ public static class Composite_C1Console_Trees { public static string GenericEditDataAction_DefaultLabel=>T("GenericEditDataAction.DefaultLabel"); ///"Delete" public static string GenericDeleteDataAction_DefaultLabel=>T("GenericDeleteDataAction.DefaultLabel"); +///"Duplicate" +public static string GenericDuplicateDataAction_DefaultLabel=>T("GenericDuplicateDataAction.DefaultLabel"); ///"Cascade delete error" public static string TreeGenericDelete_CascadeDeleteErrorTitle=>T("TreeGenericDelete.CascadeDeleteErrorTitle"); ///"The type is referenced by another type that does not allow cascade deletes. This operation is halted" @@ -338,15 +340,15 @@ public static class Composite_C1Console_Users { public static string ChangeOwnCultureWorkflow_ElementActionLabel=>T("ChangeOwnCultureWorkflow.ElementActionLabel"); ///"Set the C1 Console language and formatting of numbers, times and dates" public static string ChangeOwnCultureWorkflow_ElementActionToolTip=>T("ChangeOwnCultureWorkflow.ElementActionToolTip"); -///"Regional Settings and Language" +///"Profile Settings" public static string ChangeOwnCultureWorkflow_Dialog_Label=>T("ChangeOwnCultureWorkflow.Dialog.Label"); ///"Display Preferences" public static string ChangeOwnCultureWorkflow_Dialog_CultureSelector_Label=>T("ChangeOwnCultureWorkflow.Dialog.CultureSelector.Label"); -///"Select from the list of options to update how time, date, and number formats are displayed within the console." +///"Display for time, date, and number formats within the console" public static string ChangeOwnCultureWorkflow_Dialog_CultureSelector_Help=>T("ChangeOwnCultureWorkflow.Dialog.CultureSelector.Help"); ///"Console Language Preferences" public static string ChangeOwnCultureWorkflow_Dialog_C1ConsoleLanguageSelector_Label=>T("ChangeOwnCultureWorkflow.Dialog.C1ConsoleLanguageSelector.Label"); -///"Select the language to be used for labels, help texts, dialogs etc. The available options here are limited to languages installed. You may install more languages via the Package system, see Composite.Localization." +///"Language displayed within your console for labels, help texts, dialogs, etc. The available options are limited to language packages installed. See Composite.Localization package for more language options." public static string ChangeOwnCultureWorkflow_Dialog_C1ConsoleLanguageSelector_Help=>T("ChangeOwnCultureWorkflow.Dialog.C1ConsoleLanguageSelector.Help"); ///"Change application language" public static string ChangeOwnCultureWorkflow_Dialog_Confirm_Title=>T("ChangeOwnCultureWorkflow.Dialog.Confirm.Title"); @@ -1179,13 +1181,13 @@ public static class Composite_Management { public static string Website_Forms_Administrative_EditUserStep1_GroupHelp=>T("Website.Forms.Administrative.EditUserStep1.GroupHelp"); ///"C1 Console Localization" public static string Website_Forms_Administrative_EditUserStep1_LabelLocalizationFieldGroup=>T("Website.Forms.Administrative.EditUserStep1.LabelLocalizationFieldGroup"); -///"Regional settings" +///"Display Preferences" public static string Website_Forms_Administrative_EditUserStep1_CultureLabel=>T("Website.Forms.Administrative.EditUserStep1.CultureLabel"); -///"To change the way numbers, dates, and hours are displayed, select an entry from the list." +///"Display for time, date, and number formats within the console" public static string Website_Forms_Administrative_EditUserStep1_CultureHelp=>T("Website.Forms.Administrative.EditUserStep1.CultureHelp"); -///"C1 Console Language" +///"Console Language Preferences" public static string Website_Forms_Administrative_EditUserStep1_C1ConsoleLanguageLabel=>T("Website.Forms.Administrative.EditUserStep1.C1ConsoleLanguageLabel"); -///"Select the language to be used for labels, help texts, dialogs etc. The available options here are limited to languages installed. You may install more languages via the Package system, see Composite.Localization." +///"Language displayed within your console for labels, help texts, dialogs, etc. The available options are limited to language packages installed. See Composite.Localization package for more language options." public static string Website_Forms_Administrative_EditUserStep1_C1ConsoleLanguageHelp=>T("Website.Forms.Administrative.EditUserStep1.C1ConsoleLanguageHelp"); ///"Perspectives" public static string Website_Forms_Administrative_EditUserStep1_ActivePerspectiveFieldLabel=>T("Website.Forms.Administrative.EditUserStep1.ActivePerspectiveFieldLabel"); @@ -1285,13 +1287,13 @@ public static class Composite_Management { public static string Website_Forms_Administrative_AddNewUserStep1_GroupLabel=>T("Website.Forms.Administrative.AddNewUserStep1.GroupLabel"); ///"If you enter a folder name that does not already exist a new folder will be created." public static string Website_Forms_Administrative_AddNewUserStep1_GroupHelp=>T("Website.Forms.Administrative.AddNewUserStep1.GroupHelp"); -///"Regional settings" +///"Display Preferences" public static string Website_Forms_Administrative_AddNewUserStep1_CultureLabel=>T("Website.Forms.Administrative.AddNewUserStep1.CultureLabel"); -///"To change the way numbers, dates, and hours are displayed, select an entry from the list." +///"Display for time, date, and number formats within the console" public static string Website_Forms_Administrative_AddNewUserStep1_CultureHelp=>T("Website.Forms.Administrative.AddNewUserStep1.CultureHelp"); -///"C1 Console Language" +///"Console Language Preferences" public static string Website_Forms_Administrative_AddNewUserStep1_C1ConsoleLanguageLabel=>T("Website.Forms.Administrative.AddNewUserStep1.C1ConsoleLanguageLabel"); -///"Select the language to be used for labels, help texts, dialogs etc. The available options here are limited to languages installed. You may install more languages via the Package system, see Composite.Localization." +///"Language displayed within your console for labels, help texts, dialogs, etc. The available options are limited to language packages installed. See Composite.Localization package for more language options." public static string Website_Forms_Administrative_AddNewUserStep1_C1ConsoleLanguageHelp=>T("Website.Forms.Administrative.AddNewUserStep1.C1ConsoleLanguageHelp"); ///"A language is required" public static string UserElementProvider_MissingActiveLanguageTitle=>T("UserElementProvider.MissingActiveLanguageTitle"); @@ -1315,6 +1317,10 @@ public static class Composite_Management { public static string AssociatedDataElementProviderHelper_DeleteAssociatedDataLabel=>T("AssociatedDataElementProviderHelper.DeleteAssociatedDataLabel"); ///"Delete data" public static string AssociatedDataElementProviderHelper_DeleteAssociatedDataToolTip=>T("AssociatedDataElementProviderHelper.DeleteAssociatedDataToolTip"); +///"Duplicate Data" +public static string AssociatedDataElementProviderHelper_DuplicateAssociatedDataLabel=>T("AssociatedDataElementProviderHelper.DuplicateAssociatedDataLabel"); +///"Duplicate data" +public static string AssociatedDataElementProviderHelper_DuplicateAssociatedDataToolTip=>T("AssociatedDataElementProviderHelper.DuplicateAssociatedDataToolTip"); ///"Localize" public static string AssociatedDataElementProviderHelper_LocalizeData=>T("AssociatedDataElementProviderHelper.LocalizeData"); ///"Localize data" @@ -2453,6 +2459,8 @@ public static class Composite_Management { public static string Browser_Label=>T("Browser.Label"); ///"Browse unpublished pages" public static string Browser_ToolTip=>T("Browser.ToolTip"); +///"Copy{count} of {0}" +public static string Duplication_Text(object parameter0)=>string.Format(T("Duplication.Text"), parameter0); private static string T(string key) { return StringResourceSystemFacade.GetString("Composite.Management", key); @@ -2661,6 +2669,10 @@ public static class Composite_Plugins_GeneratedDataTypesElementProvider { public static string DeleteData=>T("DeleteData"); ///"Delete selected data" public static string DeleteDataToolTip=>T("DeleteDataToolTip"); +///"Duplicate Data" +public static string DuplicateData=>T("DuplicateData"); +///"Duplicate selected data" +public static string DuplicateDataToolTip=>T("DuplicateDataToolTip"); ///"Translate Data" public static string LocalizeData=>T("LocalizeData"); ///"Translate selected data" @@ -3591,6 +3603,10 @@ public static class Composite_Plugins_PageElementProvider { public static string PageElementProvider_Delete=>T("PageElementProvider.Delete"); ///"Delete the selected page" public static string PageElementProvider_DeleteToolTip=>T("PageElementProvider.DeleteToolTip"); +///"Duplicate" +public static string PageElementProvider_Duplicate=>T("PageElementProvider.Duplicate"); +///"Duplicate the selected page" +public static string PageElementProvider_DuplicateToolTip=>T("PageElementProvider.DuplicateToolTip"); ///"Translate Page" public static string PageElementProvider_LocalizePage=>T("PageElementProvider.LocalizePage"); ///"Translate selected page" @@ -3671,11 +3687,11 @@ public static class Composite_Plugins_PageElementProvider { public static string ViewUnpublishedItems_StatusLabel=>T("ViewUnpublishedItems.StatusLabel"); ///"Publish Date" public static string ViewUnpublishedItems_PublishDateLabel=>T("ViewUnpublishedItems.PublishDateLabel"); -///"This is the date and time that has been set for the page to be published automatically. To update or remove, see the Publication Schedule in Edit Page mode. Otherwise you can override these dates by publishing manually from this view." +///"Date and time the page has been scheduled to publish automatically. To edit, see the Publication Schedule in Edit Page mode." public static string ViewUnpublishedItems_PublishDateHelp=>T("ViewUnpublishedItems.PublishDateHelp"); ///"Unpublish Date" public static string ViewUnpublishedItems_UnpublishDateLabel=>T("ViewUnpublishedItems.UnpublishDateLabel"); -///"This is the date and time that has been set for the page to be unpublished automatically. To update or remove, see the Publication Schedule in Edit Page mode." +///"Date and time the page has been scheduled to unpublish automatically. To edit, see the Publication Schedule in Edit Page mode." public static string ViewUnpublishedItems_UnpublishDateHelp=>T("ViewUnpublishedItems.UnpublishDateHelp"); ///"Date Created" public static string ViewUnpublishedItems_DateCreatedLabel=>T("ViewUnpublishedItems.DateCreatedLabel"); diff --git a/Website/Composite/localization/Composite.Management.en-us.xml b/Website/Composite/localization/Composite.Management.en-us.xml index f42127355f..ebbbfbe059 100644 --- a/Website/Composite/localization/Composite.Management.en-us.xml +++ b/Website/Composite/localization/Composite.Management.en-us.xml @@ -106,6 +106,8 @@ + + @@ -679,4 +681,6 @@ + + From 0ccecbbf49e71f0e8e099ff28e9fad075c73ce56 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 29 Aug 2016 17:50:21 +0200 Subject: [PATCH 04/95] Adding duplicate action token to data elements --- .../AssociatedDataElementProviderHelper.cs | 30 +++++++++++++++++++ Composite/Composite.csproj | 4 ++- ...atedDataTypesElementDynamicActionTokens.cs | 5 ++-- .../GeneratedDataTypesElementProvider.cs | 21 +++++++++++++ .../PageElementDynamicActionTokens.cs | 2 ++ .../PageElementProvider.cs | 22 ++++++++++++++ 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs index 2ed6a434da..77fa989382 100644 --- a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs +++ b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Composite.C1Console.Actions.Data; using Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper; using Composite.C1Console.Security; using Composite.C1Console.Users; @@ -43,6 +44,7 @@ internal sealed class AssociatedDataElementProviderHelper : IAuxiliarySecurit private ResourceHandle AddAssociatedDataIcon { get { return GetIconHandle("associated-data-add"); } } private ResourceHandle EditAssociatedDataIcon { get { return GetIconHandle("associated-data-edit"); } } private ResourceHandle DeleteAssociatedDataIcon { get { return GetIconHandle("associated-data-delete"); } } + private ResourceHandle DuplicateAssociatedDataIcon { get { return GetIconHandle("copy"); } } public static ResourceHandle LocalizeDataIcon { get { return GetIconHandle("generated-type-data-localize"); } } @@ -379,6 +381,7 @@ private Element CreateElement(IData data) AddEditAssociatedDataAction(element); AddDeleteAssociatedDataAction(element); + AddDuplicateAssociatedDataAction(element); if (InternalUrls.DataTypeSupported(data.DataSourceId.InterfaceType)) { @@ -516,6 +519,33 @@ private void AddDeleteAssociatedDataAction(Element element) } }); } + + private void AddDuplicateAssociatedDataAction(Element element) + { + element.AddAction(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Duplicate, + _addAssociatedDataPermissionTypes))) + { + VisualData = new ActionVisualizedData + { + Label = + StringResourceSystemFacade.GetString("Composite.Management", + "AssociatedDataElementProviderHelper.DuplicateAssociatedDataLabel"), + ToolTip = + StringResourceSystemFacade.GetString("Composite.Management", + "AssociatedDataElementProviderHelper.DuplicateAssociatedDataToolTip"), + Icon = this.DuplicateAssociatedDataIcon, + Disabled = false, + ActionLocation = new ActionLocation + { + ActionType = ActionType.Add, + IsInFolder = false, + IsInToolbar = true, + ActionGroup = PrimaryActionGroup + } + } + }); + + } #endregion diff --git a/Composite/Composite.csproj b/Composite/Composite.csproj index b9a1b1b116..8bfba73637 100644 --- a/Composite/Composite.csproj +++ b/Composite/Composite.csproj @@ -168,8 +168,10 @@ + + @@ -2523,4 +2525,4 @@ copy "$(TargetPath)" "$(ProjectDir)..\bin\" copy "$(TargetPath)" "$(ProjectDir)..\Website\bin\" - + \ No newline at end of file diff --git a/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs b/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs index ff80aaaffd..cd10c794bf 100644 --- a/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs +++ b/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementDynamicActionTokens.cs @@ -1,8 +1,8 @@ -using Composite.C1Console.Actions.Data; +using Composite.C1Console.Actions; +using Composite.C1Console.Actions.Data; using Composite.C1Console.Workflow; using Composite.Core.Application; using Composite.Data; -using Composite.Data.Types; namespace Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider { @@ -17,6 +17,7 @@ public static void OnBeforeInitialize() { DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Edit, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider.EditDataWorkflow"))); DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Delete, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.GeneratedDataTypesElementProvider.DeleteDataWorkflow"))); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Duplicate, f => new DuplicateActionToken()); } /// public static void OnInitialized() diff --git a/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementProvider.cs index 15d514aa18..704cf77875 100644 --- a/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/GeneratedDataTypesElementProvider/GeneratedDataTypesElementProvider.cs @@ -140,6 +140,9 @@ internal sealed class GeneratedDataTypesElementProvider : IHooklessElementProvid /// public static ResourceHandle AddDataIcon { get { return GetIconHandle("generated-type-data-add"); } } + /// + public static ResourceHandle DuplicateDataIcon { get { return GetIconHandle("copy"); } } + /// public static ResourceHandle EditDataIcon { get { return GetIconHandle("generated-type-data-edit"); } } @@ -1095,6 +1098,24 @@ private Element GetElementFromData(IData data) } } }); + element.AddAction( + new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Duplicate, _addNewDataPermissionTypes))) + { + VisualData = new ActionVisualizedData + { + Label = GetText("DuplicateData"), + ToolTip = GetText("DuplicateDataToolTip"), + Icon = GeneratedDataTypesElementProvider.DuplicateDataIcon, + Disabled = false, + ActionLocation = new ActionLocation + { + ActionType = ActionType.Add, + IsInFolder = false, + IsInToolbar = true, + ActionGroup = PrimaryActionGroup + } + } + }); } return element; diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs index 63fbba270d..f307f044e2 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementDynamicActionTokens.cs @@ -1,3 +1,4 @@ +using Composite.C1Console.Actions; using Composite.C1Console.Actions.Data; using Composite.C1Console.Workflow; using Composite.Core.Application; @@ -18,6 +19,7 @@ public static void OnBeforeInitialize() DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Add, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.AddNewPageWorkflow")) { DoIgnoreEntityTokenLocking = true, Payload = SerializerHandlerFacade.Serialize(f) }); DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Edit, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.EditPageWorkflow"))); DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Delete, f => new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.Plugins.Elements.ElementProviders.PageElementProvider.DeletePageWorkflow"))); + DataActionTokenResolverFacade.RegisterDefault(ActionIdentifier.Duplicate, f => new DuplicateActionToken()); } /// diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs index 13105a4f84..cebdc80d7f 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs @@ -36,6 +36,7 @@ internal class PageElementProvider : IHooklessElementProvider, IDataExchangingEl private AssociatedDataElementProviderHelper _pageAssociatedHelper; + public static ResourceHandle DuplicatePage = GetIconHandle("copy"); public static ResourceHandle EditPage = GetIconHandle("page-edit-page"); public static ResourceHandle LocalizePage = GetIconHandle("page-localize-page"); public static ResourceHandle ManageHostNames = GetIconHandle("page-manage-host-names"); @@ -63,6 +64,7 @@ internal class PageElementProvider : IHooklessElementProvider, IDataExchangingEl private static readonly ActionGroup MetaDataAppendedActionGroup = new ActionGroup("Associated data", ActionGroupPriority.PrimaryMedium); internal static readonly List AddWebsitePermissionTypes = new List { PermissionType.Configure, PermissionType.Administrate }; internal static readonly List EditPermissionTypes = new List { PermissionType.Edit }; + internal static readonly List DuplicatePermissionTypes = new List { PermissionType.Add }; internal static readonly List LocalizePermissionTypes = new List { PermissionType.Edit }; internal static readonly List AddPermissionTypes = new List { PermissionType.Add }; internal static readonly List DeletePermissionTypes = new List { PermissionType.Delete }; @@ -663,6 +665,8 @@ private List GetElements(List> pag string addNewPageToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.AddSubPageToolTip"); string deletePageLabel = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.Delete"); string deletePageToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.DeleteToolTip"); + string duplicatePageLabel = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.Duplicate"); + string duplicatePageToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.DuplicateToolTip"); string urlMappingName = null; if (UserSettings.ForeignLocaleCultureInfo != null) @@ -711,6 +715,24 @@ private List GetElements(List> pag } }); + element.AddAction(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Duplicate, DuplicatePermissionTypes))) + { + VisualData = new ActionVisualizedData + { + Label = duplicatePageLabel, + ToolTip = duplicatePageToolTip, + Icon = PageElementProvider.DuplicatePage, + Disabled = false, + ActionLocation = new ActionLocation + { + ActionType = ActionType.Add, + IsInFolder = false, + IsInToolbar = true, + ActionGroup = PrimaryActionGroup + } + } + }); + IPageType parentPageType = allPageTypes.First(f => f.Id == page.PageTypeId); foreach (var pageType in page.GetChildPageSelectablePageTypes().OrderByDescending(pt => pt.Id == parentPageType.DefaultChildPageType)) From d6e2956c66fabd48e88502573d3664236afb73d2 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 29 Aug 2016 17:51:22 +0200 Subject: [PATCH 05/95] adding duplicate action to generic action node factory - using proxy action data in edit and delete --- .../Foundation/ActionNodeCreatorFactory.cs | 9 ++ .../Trees/GenericDeleteDataActionNode.cs | 5 +- .../Trees/GenericDuplicateDataActionNode.cs | 151 ++++++++++++++++++ .../Trees/GenericEditDataActionNode.cs | 22 ++- 4 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs diff --git a/Composite/C1Console/Trees/Foundation/ActionNodeCreatorFactory.cs b/Composite/C1Console/Trees/Foundation/ActionNodeCreatorFactory.cs index f268da01c3..778732687d 100644 --- a/Composite/C1Console/Trees/Foundation/ActionNodeCreatorFactory.cs +++ b/Composite/C1Console/Trees/Foundation/ActionNodeCreatorFactory.cs @@ -18,6 +18,7 @@ internal static class ActionNodeCreatorFactory private static readonly string DefaultAddDataResourceName = "generated-type-data-add"; private static readonly string DefaultEditDataResourceName = "generated-type-data-edit"; private static readonly string DefaultDeleteDataResourceName = "generated-type-data-delete"; + private static readonly string DefaultDuplicateDataResourceName = "generated-type-data-duplicate"; private static readonly string DefaultReportFunctionResourceName = "reportfunctionaction-defaulticon"; private static readonly string DefaultMessageBoxResourceName = "messageboxaction-defaulticon"; private static readonly string DefaultCustomUrlResourceName = "customurlaction-defaulticon"; @@ -28,6 +29,7 @@ internal static class ActionNodeCreatorFactory private static readonly List DefaultAddPermissionTypes = new List { PermissionType.Add }; private static readonly List DefaultEditPermissionTypes = new List { PermissionType.Edit }; private static readonly List DefaultDeletePermissionTypes = new List { PermissionType.Delete }; + private static readonly List DefaultDuplicatePermissionTypes = new List { PermissionType.Add }; public static ActionNode CreateActionNode(XElement element, Tree tree) @@ -72,6 +74,13 @@ public static ActionNode CreateActionNode(XElement element, Tree tree) return actionNode; } + else if (element.Name == TreeMarkupConstants.Namespace + "DuplicateDataAction") + { + GenericDuplicateDataActionNode actionNode = new GenericDuplicateDataActionNode(); + InitializeWithCommonValue(element, tree, actionNode, DefaultDuplicateDataResourceName, StringResourceSystemFacade.GetString("Composite.C1Console.Trees", "GenericDuplicateDataAction.DefaultLabel"), ActionLocation.OtherPrimaryActionLocation, DefaultDuplicatePermissionTypes); + + return actionNode; + } else if (element.Name == TreeMarkupConstants.Namespace + "ReportFunctionAction") { ReportFunctionActionNode actionNode = new ReportFunctionActionNode(); diff --git a/Composite/C1Console/Trees/GenericDeleteDataActionNode.cs b/Composite/C1Console/Trees/GenericDeleteDataActionNode.cs index de6b82e079..67823561ec 100644 --- a/Composite/C1Console/Trees/GenericDeleteDataActionNode.cs +++ b/Composite/C1Console/Trees/GenericDeleteDataActionNode.cs @@ -1,8 +1,7 @@ using System; +using Composite.C1Console.Actions.Data; using Composite.C1Console.Elements; -using Composite.Core.ResourceSystem; using Composite.C1Console.Security; -using Composite.C1Console.Workflow; namespace Composite.C1Console.Trees @@ -11,7 +10,7 @@ internal sealed class GenericDeleteDataActionNode : ActionNode { protected override void OnAddAction(Action actionAdder, EntityToken entityToken, TreeNodeDynamicContext dynamicContext, DynamicValuesHelperReplaceContext dynamicValuesHelperReplaceContext) { - actionAdder(new ElementAction(new ActionHandle(new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.C1Console.Trees.Workflows.GenericDeleteDataWorkflow"), this.PermissionTypes))) + actionAdder(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Delete,this.PermissionTypes))) { VisualData = CreateActionVisualizedData(dynamicValuesHelperReplaceContext) }); diff --git a/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs b/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs new file mode 100644 index 0000000000..28acb16ba2 --- /dev/null +++ b/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; +using Composite.C1Console.Actions.Data; +using Composite.C1Console.Elements; +using Composite.C1Console.Security; +using Composite.Core.IO; +using Composite.Core.ResourceSystem; +using Composite.Core.ResourceSystem.Icons; +using Composite.Core.Xml; +using Composite.Data; + + +namespace Composite.C1Console.Trees +{ + /// + /// + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GenericDuplicateDataActionNode : ActionNode + { + /// + public Type InterfaceType { get; internal set; } // Requried + + /// + public string CustomFormMarkupPath { get; internal set; } // Optional + + + // Cached + private List ParentIdEntries { get; set; } + + + /// + protected override void OnAddAction(Action actionAdder, EntityToken entityToken, TreeNodeDynamicContext dynamicContext, DynamicValuesHelperReplaceContext dynamicValuesHelperReplaceContext) + { + actionAdder(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Duplicate,this.PermissionTypes))) + { + VisualData = CreateActionVisualizedData(dynamicValuesHelperReplaceContext) + }); + } + + + + /// + protected override void OnInitialize() + { + Icon = new ResourceHandle(BuildInIconProviderName.ProviderName, "copy"); + + if ((this.InterfaceType != null) && (typeof(IData).IsAssignableFrom(this.InterfaceType) == false)) + { + AddValidationError("TreeValidationError.Common.NotImplementingIData", this.InterfaceType, typeof(IData)); + } + + this.ParentIdEntries = new List(); + + IEnumerable treeNodes = this.OwnerNode.Descendants(true).ToList(); + foreach (TreeNode treeNode in treeNodes) + { + DataFilteringTreeNode dataFilteringTreeNode = treeNode as DataFilteringTreeNode; + + if (dataFilteringTreeNode == null) continue; + + IEnumerable parentIdFilterNodes = dataFilteringTreeNode.FilterNodes.OfType(); + if (parentIdFilterNodes.Count() == 0) continue; + + foreach (ParentIdFilterNode parentIdFilterNode in parentIdFilterNodes) + { + Type interfaceType = parentIdFilterNode.ParentFilterType; + + IEnumerable foreignPropertyInfos = DataReferenceFacade.GetForeignKeyProperties(this.InterfaceType, interfaceType); + + foreach (ForeignPropertyInfo foreignPropertyInfo in foreignPropertyInfos) + { + ParentIdEntry parentIdEntry = new ParentIdEntry + { + TargetInterface = interfaceType, + TargetPropertyInfo = foreignPropertyInfo.TargetKeyPropertyInfo, + SourcePropertyName = foreignPropertyInfo.SourcePropertyName + }; + + if (this.ParentIdEntries.Contains(parentIdEntry) == false) + { + this.ParentIdEntries.Add(parentIdEntry); + } + } + } + } + + if (string.IsNullOrEmpty(this.CustomFormMarkupPath) == false) + { + try + { + string path = PathUtil.Resolve(this.CustomFormMarkupPath); + if (C1File.Exists(path) == false) + { + AddValidationError("TreeValidationError.GenericDuplicateDataAction.MissingMarkupFile", path); + } + + XDocument document = XDocumentUtils.Load(path); + + this.CustomFormMarkupPath = path; + } + catch + { + AddValidationError("TreeValidationError.GenericDuplicateDataAction.BadMarkupPath", this.CustomFormMarkupPath); + } + } + } + + + + /// + public override string ToString() + { + return string.Format("GenericDuplicateDataActionNode, InterfaceType = {0}, Label = {1}", this.InterfaceType, this.Label); + } + + + + [DebuggerDisplay("{SourcePropertyName} -> {TargetInterface}")] + private sealed class ParentIdEntry + { + public Type TargetInterface { get; set; } + public PropertyInfo TargetPropertyInfo { get; set; } + public string SourcePropertyName { get; set; } + + public override bool Equals(object obj) + { + return Equals(obj as ParentIdEntry); + } + + public bool Equals(ParentIdEntry parentIdEntry) + { + if (parentIdEntry == null) return false; + + return + parentIdEntry.TargetInterface == this.TargetInterface && + parentIdEntry.TargetPropertyInfo == this.TargetPropertyInfo && + parentIdEntry.SourcePropertyName == this.SourcePropertyName; + } + + public override int GetHashCode() + { + return this.TargetInterface.GetHashCode() ^ this.TargetPropertyInfo.GetHashCode() ^ this.SourcePropertyName.GetHashCode(); + } + } + } +} diff --git a/Composite/C1Console/Trees/GenericEditDataActionNode.cs b/Composite/C1Console/Trees/GenericEditDataActionNode.cs index 34a08bf681..0617c35a13 100644 --- a/Composite/C1Console/Trees/GenericEditDataActionNode.cs +++ b/Composite/C1Console/Trees/GenericEditDataActionNode.cs @@ -1,6 +1,7 @@ using System; using System.Text; using System.Xml.Linq; +using Composite.C1Console.Actions.Data; using Composite.C1Console.Elements; using Composite.C1Console.Security; using Composite.C1Console.Workflow; @@ -32,15 +33,22 @@ protected override void OnAddAction(Action actionAdder, EntityTok if (!String.IsNullOrEmpty(CustomFormMarkupPath)) { StringConversionServices.SerializeKeyValuePair(payload, "_CustomFormMarkupPath_", CustomFormMarkupPath); - } - actionAdder(new ElementAction(new ActionHandle(new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.C1Console.Trees.Workflows.GenericEditDataWorkflow"), this.PermissionTypes) - { - Payload = payload.ToString() - })) + actionAdder(new ElementAction(new ActionHandle(new WorkflowActionToken(WorkflowFacade.GetWorkflowType("Composite.C1Console.Trees.Workflows.GenericEditDataWorkflow"), this.PermissionTypes) + { + Payload = payload.ToString() + })) + { + VisualData = CreateActionVisualizedData(dynamicValuesHelperReplaceContext) + }); + } + else { - VisualData = CreateActionVisualizedData(dynamicValuesHelperReplaceContext) - }); + actionAdder(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Edit, this.PermissionTypes))) + { + VisualData = CreateActionVisualizedData(dynamicValuesHelperReplaceContext) + }); + } } From 75365b2724ab8b80a2640d78dbe171f342d88215 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 29 Aug 2016 17:52:30 +0200 Subject: [PATCH 06/95] add DuplicateDataAction to available tree actions --- Website/Composite/schemas/Trees/Tree.xsd | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Website/Composite/schemas/Trees/Tree.xsd b/Website/Composite/schemas/Trees/Tree.xsd index 1916930318..4c96929adf 100644 --- a/Website/Composite/schemas/Trees/Tree.xsd +++ b/Website/Composite/schemas/Trees/Tree.xsd @@ -159,6 +159,7 @@ + @@ -1033,6 +1034,26 @@ + + + This defines a simple element (or folder) + + + + + The label of the action. Defaults to the localized version of the string 'delete' + + + + + + The tool tip of the action. Defaults to the label + + + + + + From d2988bb9448fb444ebb3cf6f25685248494d5f49 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 29 Aug 2016 17:52:47 +0200 Subject: [PATCH 07/95] Localizations --- .../Composite/localization/Composite.C1Console.Trees.en-us.xml | 1 + ...omposite.Plugins.GeneratedDataTypesElementProvider.en-us.xml | 2 ++ .../Composite.Plugins.PageElementProvider.en-us.xml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml b/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml index 66d9afe4d7..4f89ce666b 100644 --- a/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml +++ b/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml @@ -98,6 +98,7 @@ + diff --git a/Website/Composite/localization/Composite.Plugins.GeneratedDataTypesElementProvider.en-us.xml b/Website/Composite/localization/Composite.Plugins.GeneratedDataTypesElementProvider.en-us.xml index d79786e439..0184ac9e85 100644 --- a/Website/Composite/localization/Composite.Plugins.GeneratedDataTypesElementProvider.en-us.xml +++ b/Website/Composite/localization/Composite.Plugins.GeneratedDataTypesElementProvider.en-us.xml @@ -48,6 +48,8 @@ + + diff --git a/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml b/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml index fdbcacfeb6..4d41180a80 100644 --- a/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml +++ b/Website/Composite/localization/Composite.Plugins.PageElementProvider.en-us.xml @@ -74,6 +74,8 @@ + + From 42c112d724beec702edd9c34da6f26d53651d580 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Tue, 30 Aug 2016 12:57:06 +0200 Subject: [PATCH 08/95] fix for always coping application --- Composite/C1Console/Actions/DuplicateActionToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composite/C1Console/Actions/DuplicateActionToken.cs b/Composite/C1Console/Actions/DuplicateActionToken.cs index 634a558e17..f926e205bc 100644 --- a/Composite/C1Console/Actions/DuplicateActionToken.cs +++ b/Composite/C1Console/Actions/DuplicateActionToken.cs @@ -230,7 +230,7 @@ internal void CopyPageData(IPage sourcePage, IPage newPage) } List selectableTreeIds = TreeFacade.AllTrees.Where( - tree => tree.HasPossibleAttachmentPoints(sourcePage.GetDataEntityToken())) + tree => tree.HasAttachmentPoints(sourcePage.GetDataEntityToken())) .Where(tree => !tree.HasAttachmentPoints(newPage.GetDataEntityToken())) .Select(tree => tree.TreeId).ToList(); From 2e8a2b9471575a50852a7b42b0ccdab071773e08 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Tue, 30 Aug 2016 17:42:13 +0200 Subject: [PATCH 09/95] fixes, Inherited meta data bug, long string after duplication bug, regex for copy text detection , generic duplicate action --- .../C1Console/Actions/DuplicateActionToken.cs | 23 ++-- .../Trees/GenericDuplicateDataActionNode.cs | 113 +----------------- 2 files changed, 19 insertions(+), 117 deletions(-) diff --git a/Composite/C1Console/Actions/DuplicateActionToken.cs b/Composite/C1Console/Actions/DuplicateActionToken.cs index f926e205bc..45e8d32735 100644 --- a/Composite/C1Console/Actions/DuplicateActionToken.cs +++ b/Composite/C1Console/Actions/DuplicateActionToken.cs @@ -15,6 +15,7 @@ using Composite.Core.ResourceSystem; using Composite.Core.Types; using Composite.Data; +using Composite.Data.DynamicTypes; using Composite.Data.DynamicTypes.Foundation; using Composite.Data.ProcessControlled; using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; @@ -137,11 +138,14 @@ private bool SetNewValue( IData sourceData, IData newData, PropertyInfo prope var value = isUrl? (string)property.GetValue(sourceData): GetStringWithoutCopyOf((string) property.GetValue(sourceData)); + var storeFieldType = property.GetCustomAttributes(true).FirstOrDefault(f=>f is StoreFieldTypeAttribute); + var maxLength = (storeFieldType as StoreFieldTypeAttribute)?.StoreFieldType.MaximumLength; + if (!isUrl && value.IsNullOrEmpty()) return false; for (var count = 1;; count++) { - var str = GenerateCopyOfName(value, count,isUrl); + var str = GenerateCopyOfName(value, count, maxLength, isUrl); if (DataFacade.GetData().Any(GetLambda(property, str))) continue; property.SetValue(newData, str); break; @@ -159,12 +163,12 @@ private Expression> GetLambda(PropertyInfo labelProperty, strin private static string GetStringWithoutCopyOf(string source) { - Regex regexInstance = new Regex(StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text").Replace("{count}", ".*")+ " "); + Regex regexInstance = new Regex(StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text").Replace("{0}","").Replace("{count}", @"(\(.*\))*")); return regexInstance.Replace(source, ""); } - private string GenerateCopyOfName(string source, int count,bool isUrl=false) + private string GenerateCopyOfName(string source, int count, int? maxLength, bool isUrl=false ) { if (isUrl) { @@ -173,7 +177,8 @@ private string GenerateCopyOfName(string source, int count,bool isUrl=false) Func copyText = i => StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text") .Replace("{count}", i == 1 ? "" : $"({i})"); - return string.Format(copyText(count), source); + var result = string.Format(copyText(count), source); + return (maxLength!=null)?result.Substring(0, Math.Min(result.Length, maxLength.Value)):result; } internal void CopyPageData(IPage sourcePage, IPage newPage) @@ -223,10 +228,14 @@ internal void CopyPageData(IPage sourcePage, IPage newPage) newDataItem.Id = Guid.NewGuid(); newDataItem.PageId = newPageId; newDataItem.PublicationStatus = GenericPublishProcessController.Draft; - DataFacade.AddNew((IData)newDataItem); + newDataItem = (IPageMetaData)DataFacade.AddNew((IData)newDataItem); - string title = newDataItem.GetTypeTitle(); - newPage.AddMetaDataDefinition(title, title, newDataItem.GetImmutableTypeId(), definition.MetaDataContainerId); + if (definition != null) + { + string title = newDataItem.GetTypeTitle(); + newPage.AddMetaDataDefinition(title, title, newDataItem.GetImmutableTypeId(), + definition.MetaDataContainerId); + } } List selectableTreeIds = TreeFacade.AllTrees.Where( diff --git a/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs b/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs index 28acb16ba2..c6496bcee8 100644 --- a/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs +++ b/Composite/C1Console/Trees/GenericDuplicateDataActionNode.cs @@ -22,130 +22,23 @@ namespace Composite.C1Console.Trees [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public sealed class GenericDuplicateDataActionNode : ActionNode { - /// - public Type InterfaceType { get; internal set; } // Requried - - /// - public string CustomFormMarkupPath { get; internal set; } // Optional - - - // Cached - private List ParentIdEntries { get; set; } - - /// protected override void OnAddAction(Action actionAdder, EntityToken entityToken, TreeNodeDynamicContext dynamicContext, DynamicValuesHelperReplaceContext dynamicValuesHelperReplaceContext) { + Icon = new ResourceHandle(BuildInIconProviderName.ProviderName, "copy"); + actionAdder(new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Duplicate,this.PermissionTypes))) { VisualData = CreateActionVisualizedData(dynamicValuesHelperReplaceContext) }); } - - - /// - protected override void OnInitialize() - { - Icon = new ResourceHandle(BuildInIconProviderName.ProviderName, "copy"); - - if ((this.InterfaceType != null) && (typeof(IData).IsAssignableFrom(this.InterfaceType) == false)) - { - AddValidationError("TreeValidationError.Common.NotImplementingIData", this.InterfaceType, typeof(IData)); - } - - this.ParentIdEntries = new List(); - - IEnumerable treeNodes = this.OwnerNode.Descendants(true).ToList(); - foreach (TreeNode treeNode in treeNodes) - { - DataFilteringTreeNode dataFilteringTreeNode = treeNode as DataFilteringTreeNode; - - if (dataFilteringTreeNode == null) continue; - - IEnumerable parentIdFilterNodes = dataFilteringTreeNode.FilterNodes.OfType(); - if (parentIdFilterNodes.Count() == 0) continue; - - foreach (ParentIdFilterNode parentIdFilterNode in parentIdFilterNodes) - { - Type interfaceType = parentIdFilterNode.ParentFilterType; - - IEnumerable foreignPropertyInfos = DataReferenceFacade.GetForeignKeyProperties(this.InterfaceType, interfaceType); - - foreach (ForeignPropertyInfo foreignPropertyInfo in foreignPropertyInfos) - { - ParentIdEntry parentIdEntry = new ParentIdEntry - { - TargetInterface = interfaceType, - TargetPropertyInfo = foreignPropertyInfo.TargetKeyPropertyInfo, - SourcePropertyName = foreignPropertyInfo.SourcePropertyName - }; - - if (this.ParentIdEntries.Contains(parentIdEntry) == false) - { - this.ParentIdEntries.Add(parentIdEntry); - } - } - } - } - - if (string.IsNullOrEmpty(this.CustomFormMarkupPath) == false) - { - try - { - string path = PathUtil.Resolve(this.CustomFormMarkupPath); - if (C1File.Exists(path) == false) - { - AddValidationError("TreeValidationError.GenericDuplicateDataAction.MissingMarkupFile", path); - } - - XDocument document = XDocumentUtils.Load(path); - - this.CustomFormMarkupPath = path; - } - catch - { - AddValidationError("TreeValidationError.GenericDuplicateDataAction.BadMarkupPath", this.CustomFormMarkupPath); - } - } - } - - - /// public override string ToString() { - return string.Format("GenericDuplicateDataActionNode, InterfaceType = {0}, Label = {1}", this.InterfaceType, this.Label); + return $"GenericDuplicateDataActionNode, Label = {this.Label}"; } - - [DebuggerDisplay("{SourcePropertyName} -> {TargetInterface}")] - private sealed class ParentIdEntry - { - public Type TargetInterface { get; set; } - public PropertyInfo TargetPropertyInfo { get; set; } - public string SourcePropertyName { get; set; } - - public override bool Equals(object obj) - { - return Equals(obj as ParentIdEntry); - } - - public bool Equals(ParentIdEntry parentIdEntry) - { - if (parentIdEntry == null) return false; - - return - parentIdEntry.TargetInterface == this.TargetInterface && - parentIdEntry.TargetPropertyInfo == this.TargetPropertyInfo && - parentIdEntry.SourcePropertyName == this.SourcePropertyName; - } - - public override int GetHashCode() - { - return this.TargetInterface.GetHashCode() ^ this.TargetPropertyInfo.GetHashCode() ^ this.SourcePropertyName.GetHashCode(); - } - } } } From b6718d22dfe1d1b780d99dbf50cd06c972f6e406 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 31 Aug 2016 11:59:57 +0200 Subject: [PATCH 10/95] publicized DuplicateActionToken, dupliacte root pages diffrently, change empty url copy string text --- .../C1Console/Actions/DuplicateActionToken.cs | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/Composite/C1Console/Actions/DuplicateActionToken.cs b/Composite/C1Console/Actions/DuplicateActionToken.cs index 45e8d32735..0b9d8dd489 100644 --- a/Composite/C1Console/Actions/DuplicateActionToken.cs +++ b/Composite/C1Console/Actions/DuplicateActionToken.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.RegularExpressions; -using Composite.C1Console.Elements.Plugins.ElementAttachingProvider; using Composite.C1Console.Security; using Composite.C1Console.Events; using Composite.C1Console.Trees; @@ -15,8 +12,8 @@ using Composite.Core.ResourceSystem; using Composite.Core.Types; using Composite.Data; -using Composite.Data.DynamicTypes; using Composite.Data.DynamicTypes.Foundation; +using Composite.Data.Hierarchy; using Composite.Data.ProcessControlled; using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; using Composite.Data.Types; @@ -24,9 +21,13 @@ namespace Composite.C1Console.Actions { + /// + /// Action to duplicate data + /// [ActionExecutor(typeof(DuplicateActionExecuter))] - internal class DuplicateActionToken : ActionToken + public sealed class DuplicateActionToken : ActionToken { + /// public override IEnumerable PermissionTypes => new[] { PermissionType.Add }; /// @@ -70,6 +71,8 @@ public FlowToken Execute(string serializedEntityToken, string serializedActionTo return null; } + private static readonly Func IsRootPage = f => f.GetParent() == null; + private IData CloneData(T data) where T : class, IData { IData newdata = DataFacade.BuildNew(); @@ -92,11 +95,15 @@ private IData CloneData(T data) where T : class, IData var page = data as IPage; if (page != null) { - if(!SetNewValue(page,newdata, dataProperties.First(p => p.Name == nameof(IPage.MenuTitle)))) + if (IsRootPage(page)) + { + SetNewValue(page, newdata, dataProperties.First(p => p.Name == nameof(IPage.Title))); + } + else if (!SetNewValue(page, newdata, dataProperties.First(p => p.Name == nameof(IPage.MenuTitle)))) { SetNewValue(page, newdata, dataProperties.First(p => p.Name == nameof(IPage.Title))); } - + SetNewValue(page, newdata, dataProperties.First(p => p.Name == nameof(IPage.UrlTitle)), isUrl:true); PageInsertPosition.After(page.Id).CreatePageStructure(newdata as IPage, page.GetParentId()); @@ -138,7 +145,7 @@ private bool SetNewValue( IData sourceData, IData newData, PropertyInfo prope var value = isUrl? (string)property.GetValue(sourceData): GetStringWithoutCopyOf((string) property.GetValue(sourceData)); - var storeFieldType = property.GetCustomAttributes(true).FirstOrDefault(f=>f is StoreFieldTypeAttribute); + var storeFieldType = property.GetCustomAttributes(typeof(StoreFieldTypeAttribute),true).FirstOrDefault(); var maxLength = (storeFieldType as StoreFieldTypeAttribute)?.StoreFieldType.MaximumLength; if (!isUrl && value.IsNullOrEmpty()) @@ -172,7 +179,13 @@ private string GenerateCopyOfName(string source, int count, int? maxLength, bool { if (isUrl) { - return string.Join("-", source, count.ToString()); + if (!source.IsNullOrEmpty()) + { + return string.Join("-", source, count.ToString()); + } + + return GenerateCopyOfName(source,count,maxLength).Trim().Replace(" ","-").Replace("(","").Replace(")",""); + } Func copyText = i => StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text") From 602087c71a7643183156f0ea10fb4a8d307c8e10 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Tue, 6 Sep 2016 11:32:30 +0200 Subject: [PATCH 11/95] add versioning support --- .../C1Console/Actions/DuplicateActionToken.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Composite/C1Console/Actions/DuplicateActionToken.cs b/Composite/C1Console/Actions/DuplicateActionToken.cs index 0b9d8dd489..3ab6590d17 100644 --- a/Composite/C1Console/Actions/DuplicateActionToken.cs +++ b/Composite/C1Console/Actions/DuplicateActionToken.cs @@ -81,7 +81,7 @@ private IData CloneData(T data) where T : class, IData foreach (var propertyInfo in dataProperties.Where(f => f.CanWrite)) { - if (data.GetKeyProperties().Contains(propertyInfo) && propertyInfo.PropertyType == typeof(Guid)) + if (typeof(T).GetPhysicalKeyProperties().Contains(propertyInfo) && propertyInfo.PropertyType == typeof(Guid)) { propertyInfo.SetValue(newdata, Guid.NewGuid()); } @@ -183,9 +183,8 @@ private string GenerateCopyOfName(string source, int count, int? maxLength, bool { return string.Join("-", source, count.ToString()); } - - return GenerateCopyOfName(source,count,maxLength).Trim().Replace(" ","-").Replace("(","").Replace(")",""); - + var numberInString = count == 1 ? "" : count.ToString(); + return $"Copy{numberInString}-of"; } Func copyText = i => StringResourceSystemFacade.GetString("Composite.Management", "Duplication.Text") @@ -198,13 +197,14 @@ internal void CopyPageData(IPage sourcePage, IPage newPage) { Guid sourcePageId = sourcePage.Id; Guid newPageId = newPage.Id; - //Guid sourceVersionId = sourcePage.VersionId; + Guid sourceVersionId = sourcePage.VersionId; + Guid newVersionId = newPage.VersionId; var newPlaceholders = new List(); var placeholders = DataFacade.GetData(). - Where(ph => ph.PageId == sourcePageId) - // && ph.VersionId == sourceVersionId) + Where(ph => ph.PageId == sourcePageId + && ph.VersionId == sourceVersionId) .ToList(); foreach (var placeholderContent in placeholders) @@ -214,14 +214,14 @@ internal void CopyPageData(IPage sourcePage, IPage newPage) newPlaceholder.PageId = newPageId; newPlaceholder.PlaceHolderId = placeholderContent.PlaceHolderId; newPlaceholder.Content = placeholderContent.Content; - //newPlaceholder.VersionId = newVersionId; + newPlaceholder.VersionId = newVersionId; newPlaceholders.Add(newPlaceholder); } DataFacade.AddNew(newPlaceholders); - var sourceMetaData = sourcePage.GetMetaData().Cast(); - //.Where(d => d.VersionId == sourceVersionId); + var sourceMetaData = sourcePage.GetMetaData().Cast() + .Where(d => d.VersionId == sourceVersionId); foreach (var metaDataItem in sourceMetaData) { var metaDataType = metaDataItem.DataSourceId.InterfaceType; @@ -237,7 +237,7 @@ internal void CopyPageData(IPage sourcePage, IPage newPage) propertyInfo.SetValue(newDataItem, propertyInfo.GetValue(metaDataItem)); } - //newDataItem.VersionId = newVersionId; + newDataItem.VersionId = newVersionId; newDataItem.Id = Guid.NewGuid(); newDataItem.PageId = newPageId; newDataItem.PublicationStatus = GenericPublishProcessController.Draft; From c780358204a893dd491e464c59fe1f6b7098ecfb Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Wed, 7 Sep 2016 12:07:31 +0200 Subject: [PATCH 12/95] Fixing an exception in SqlLoggerTextWriter when a query parameter isn't parsed correctly --- .../Foundation/SqlLoggerTextWriter.cs | 77 ++++++++----------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlLoggerTextWriter.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlLoggerTextWriter.cs index c9d34e96f5..82d47cea68 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlLoggerTextWriter.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlLoggerTextWriter.cs @@ -1,24 +1,26 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; -using Composite.Core.Logging; +using Composite.Core; namespace Composite.Plugins.Data.DataProviders.MSSqlServerDataProvider.Foundation { internal sealed class SqlLoggerTextWriter : System.IO.TextWriter { - private static Regex ContainsParamRegex = new Regex(@"@p[0-9]+", RegexOptions.Compiled); - private static Regex ParamRegex = new Regex(@"-- (?@p[0-9]+):", RegexOptions.Compiled); + private static readonly Regex ContainsParamRegex = new Regex(@"@(p|x)[0-9]+", RegexOptions.Compiled); + private static readonly Regex ParamRegex = new Regex(@"-- (?@(p|x)[0-9]+):", RegexOptions.Compiled); private readonly SqlLoggingContext _sqlLoggingContext; - private Dictionary>> _threadData = new Dictionary>>(); - private readonly object _lock = new object(); + private readonly ConcurrentDictionary>> _threadData + = new ConcurrentDictionary>>(); public SqlLoggerTextWriter(SqlLoggingContext sqlLoggingContext) { @@ -28,19 +30,16 @@ public SqlLoggerTextWriter(SqlLoggingContext sqlLoggingContext) - public override Encoding Encoding - { - get { return Encoding.UTF8; } - } + public override Encoding Encoding => Encoding.UTF8; public override void WriteLine(string value) { - if (value.StartsWith("--") == false) + if (!value.StartsWith("--")) { HandleNewQuery(value); } - else if (value.StartsWith("-- Context:") == false) + else if (!value.StartsWith("-- Context:")) { HandleParameter(value); } @@ -54,9 +53,9 @@ public override void WriteLine(string value) private void HandleNewQuery(string value) { - foreach (string tableToIgnore in _sqlLoggingContext.TablesToIgnore) + if (_sqlLoggingContext.TablesToIgnore.Any(value.Contains)) { - if (value.Contains(tableToIgnore)) return; + return; } @@ -68,31 +67,32 @@ private void HandleNewQuery(string value) return; } - Tuple> entry = new Tuple>(value, new Dictionary()); - lock (_lock) - { - _threadData.Add(Thread.CurrentThread.ManagedThreadId, entry); - } + var entry = new Tuple>(value, new Dictionary()); + + _threadData[Thread.CurrentThread.ManagedThreadId] = entry; } private void HandleParameter(string value) { - if (_threadData.ContainsKey(Thread.CurrentThread.ManagedThreadId) == false) return; - - Match match = ParamRegex.Match(value); - string paramId = match.Groups["param"].Value; + Tuple> entry; - string paramValue = value.Substring(value.IndexOf("[")); + if (!_threadData.TryGetValue(Thread.CurrentThread.ManagedThreadId, out entry)) + { + return; + } + Match match = ParamRegex.Match(value); - Tuple> entry; - lock (_lock) + string paramId = match.Groups["param"].Value; + if (string.IsNullOrEmpty(paramId)) { - entry = _threadData[Thread.CurrentThread.ManagedThreadId]; + Log.LogWarning(nameof(SqlLoggerTextWriter), "Failed to parse parameter line: " + value); + return; } + string paramValue = value.Substring(value.IndexOf('[')); entry.Item2.Add(paramId, paramValue); } @@ -100,21 +100,11 @@ private void HandleParameter(string value) public void HandleEndQuery() { - Tuple> entry = null; + Tuple> entry; - if (_threadData.ContainsKey(Thread.CurrentThread.ManagedThreadId)) - { - lock (_lock) - { - if (_threadData.ContainsKey(Thread.CurrentThread.ManagedThreadId)) - { - entry = _threadData[Thread.CurrentThread.ManagedThreadId]; - _threadData.Remove(Thread.CurrentThread.ManagedThreadId); - } - } - } + var threadId = Thread.CurrentThread.ManagedThreadId; - if (entry != null) + if (_threadData.TryRemove(threadId, out entry)) { string value = entry.Item1; foreach (var kvp in entry.Item2) @@ -132,10 +122,11 @@ private void AddLogEntry(string value) { if (_sqlLoggingContext.IncludeStack) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); sb.AppendLine(value); sb.AppendLine("Stack trace:"); - StackTrace trace = new StackTrace(8, true); + + var trace = new StackTrace(8, true); foreach (StackFrame stackFrame in trace.GetFrames()) { MemberInfo methodInfo = stackFrame.GetMethod(); @@ -146,13 +137,13 @@ private void AddLogEntry(string value) type = methodInfo.DeclaringType.FullName; } - sb.AppendLine(string.Format(" at {0}.{1} line {2}", type, methodInfo.Name, stackFrame.GetFileLineNumber())); + sb.AppendLine($" at {type}.{methodInfo.Name} line {stackFrame.GetFileLineNumber()}"); } value = sb.ToString(); } - LoggingService.LogVerbose("RGB(0, 128, 192)SqlQuery", value); + Log.LogVerbose("RGB(0, 128, 192)SqlQuery", value); } } } From 90e4ca0d52c2a62b34d0b44fc36af09ee3930639 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 7 Sep 2016 15:24:55 +0200 Subject: [PATCH 13/95] fix bug #221 make undo change work again --- .../PageElementProvider/UndoUnpublishedChangesWorkflow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs index 67e1345391..2fc4a8a5e8 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs @@ -32,7 +32,7 @@ private void undoCodeActivity_Undo_ExecuteCode(object sender, EventArgs e) List publicCompositions = publicPage.GetMetaData(DataScopeIdentifier.Public).ToList(); Guid pageId = administrativePage.Id; - Guid versionId = administrativePage.Id; + Guid versionId = administrativePage.VersionId; List administrativePlaceholders; using (new DataScope(DataScopeIdentifier.Administrated)) From 1e4b604fab40c85d4a274d0a3ad0e141e3ed519c Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Wed, 7 Sep 2016 16:30:45 +0200 Subject: [PATCH 14/95] Fixing primary key update in relation to version fields --- .../DynamicTypes/DataTypeChangeDescriptor.cs | 55 +++++++++---------- .../Data/DynamicTypes/DataTypeDescriptor.cs | 22 ++++---- .../SqlDataProviderStoreManipulator.cs | 1 + 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/Composite/Data/DynamicTypes/DataTypeChangeDescriptor.cs b/Composite/Data/DynamicTypes/DataTypeChangeDescriptor.cs index 30018b67f9..749e1d5cff 100644 --- a/Composite/Data/DynamicTypes/DataTypeChangeDescriptor.cs +++ b/Composite/Data/DynamicTypes/DataTypeChangeDescriptor.cs @@ -14,7 +14,7 @@ public sealed class DataTypeChangeDescriptor { private readonly DataTypeDescriptor _original; private readonly DataTypeDescriptor _altered; - private bool _originalTypeDataExists = true; + private readonly bool _originalTypeDataExists; /// @@ -43,10 +43,10 @@ public bool AlteredTypeHasChanges get { bool alteredTypeHasChanges = false; - alteredTypeHasChanges |= (this.AlteredType.IsCodeGenerated != this.OriginalType.IsCodeGenerated); - alteredTypeHasChanges |= (this.AlteredType.Name != this.OriginalType.Name); + alteredTypeHasChanges |= this.AlteredType.IsCodeGenerated != this.OriginalType.IsCodeGenerated; + alteredTypeHasChanges |= this.AlteredType.Name != this.OriginalType.Name; // alteredTypeHasChanges |= (this.AlteredType.Title != this.OriginalType.Title); - alteredTypeHasChanges |= (this.AlteredType.Namespace != this.OriginalType.Namespace); + alteredTypeHasChanges |= this.AlteredType.Namespace != this.OriginalType.Namespace; // Do we really need to regenerated the type if it has a new type manager type name? //alteredTypeHasChanges |= (this.AlteredType.TypeManagerTypeName != this.OriginalType.TypeManagerTypeName); alteredTypeHasChanges |= this.AddedFields.Any(); @@ -58,6 +58,7 @@ public bool AlteredTypeHasChanges alteredTypeHasChanges |= this.AddedDataScopes.Any(); alteredTypeHasChanges |= this.DeletedDataScopes.Any(); alteredTypeHasChanges |= IndexesChanged; + alteredTypeHasChanges |= VersionKeyFieldsChanged; return alteredTypeHasChanges; } } @@ -65,27 +66,17 @@ public bool AlteredTypeHasChanges /// - public DataTypeDescriptor OriginalType - { - get { return _original; } - } - + public DataTypeDescriptor OriginalType => _original; /// - public DataTypeDescriptor AlteredType - { - get { return _altered; } - } + public DataTypeDescriptor AlteredType => _altered; /// /// True when the system contains data of the original type. Allowable schema changes can be limited when data exists. /// - public bool OriginalTypeDataExists - { - get { return _originalTypeDataExists; } - } + public bool OriginalTypeDataExists => _originalTypeDataExists; /// @@ -169,7 +160,7 @@ public IEnumerable ExistingDataScopes } - IEnumerable GetKeyProperties_Orininal() + IEnumerable GetKeyProperties_Original() { return _original.KeyPropertyNames .Select(name => _original.Fields.Where(fld => fld.Name == name) @@ -190,7 +181,7 @@ public IEnumerable DeletedKeyFields { get { - return GetKeyProperties_Orininal().Except(GetKeyProperties_Altered(), new DataFieldIdEqualityComparer()); + return GetKeyProperties_Original().Except(GetKeyProperties_Altered(), new DataFieldIdEqualityComparer()); } } @@ -202,7 +193,7 @@ public IEnumerable AddedKeyFields { get { - return GetKeyProperties_Altered().Except(GetKeyProperties_Orininal(), new DataFieldIdEqualityComparer()); + return GetKeyProperties_Altered().Except(GetKeyProperties_Original(), new DataFieldIdEqualityComparer()); } } @@ -213,27 +204,36 @@ public bool KeyFieldsOrderChanged { get { - return !GetKeyProperties_Orininal().SequenceEqual(GetKeyProperties_Altered(), new DataFieldIdEqualityComparer()); + return !GetKeyProperties_Original().SequenceEqual(GetKeyProperties_Altered(), new DataFieldIdEqualityComparer()); } } /// - /// Returns true is indexes have changed + /// Returns true if indexes have changed /// public bool IndexesChanged { get { - var origninalIndexes = OriginalType.Indexes; + var originalIndexes = OriginalType.Indexes; var newIndexes = AlteredType.Indexes; Func, string> serializeIndexes = indexes => string.Join("|", indexes.Select(i => i.ToString()).OrderBy(a => a)); - return serializeIndexes(origninalIndexes) != serializeIndexes(newIndexes); + return serializeIndexes(originalIndexes) != serializeIndexes(newIndexes); } } + + /// + /// Returns true if version key fields have changed + /// + public bool VersionKeyFieldsChanged + => !_original.VersionKeyPropertyNames.SequenceEqual(_altered.VersionKeyPropertyNames); + + + /// /// Returns key fields that exists in both the original and altered type. Fields may have changed name or type. /// @@ -287,7 +287,7 @@ private void ValidateTypeChanges() /// public class ExistingFieldInfo { - private DataFieldDescriptor _originalField; + private readonly DataFieldDescriptor _originalField; private DataFieldDescriptor _alteredField; internal ExistingFieldInfo(DataFieldDescriptor originalField, DataFieldDescriptor alteredField) @@ -297,10 +297,7 @@ internal ExistingFieldInfo(DataFieldDescriptor originalField, DataFieldDescripto } /// - public DataFieldDescriptor OriginalField - { - get { return _originalField; } - } + public DataFieldDescriptor OriginalField => _originalField; /// diff --git a/Composite/Data/DynamicTypes/DataTypeDescriptor.cs b/Composite/Data/DynamicTypes/DataTypeDescriptor.cs index b44c9935ab..f08d15761c 100644 --- a/Composite/Data/DynamicTypes/DataTypeDescriptor.cs +++ b/Composite/Data/DynamicTypes/DataTypeDescriptor.cs @@ -349,15 +349,6 @@ internal void AddSuperInterface(Type interfaceType, bool addInheritedFields) } } - foreach (string propertyName in interfaceType.GetVersionKeyPropertyNames()) - { - if (VersionKeyPropertyNames.Contains(propertyName)) continue; - - ReflectionBasedDescriptorBuilder.FindProperty(interfaceType, propertyName); - - this.VersionKeyPropertyNames.Add(propertyName, false); - } - foreach (var dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(interfaceType)) { if (!this.DataScopes.Contains(dataScopeIdentifier)) @@ -662,8 +653,7 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField XElement dataAssociationsElement = element.GetRequiredElement("DataAssociations"); XElement dataScopesElement = element.GetRequiredElement("DataScopes"); XElement keyPropertyNamesElement = element.GetRequiredElement("KeyPropertyNames"); - // TODO: check why "superInterfaceKeyPropertyNamesElement" is not used - // XElement superInterfaceKeyPropertyNamesElement = element.Element("SuperInterfaceKeyPropertyNames"); + XElement versionKeyPropertyNamesElement = element.Element("VersionKeyPropertyNames"); XElement superInterfacesElement = element.GetRequiredElement("SuperInterfaces"); XElement fieldsElement = element.GetRequiredElement("Fields"); XElement indexesElement = element.Element("Indexes"); @@ -761,6 +751,16 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField } } + if (versionKeyPropertyNamesElement != null) + { + foreach (XElement elm in keyPropertyNamesElement.Elements("VersionKeyPropertyName")) + { + var propertyName = elm.GetRequiredAttributeValue("name"); + + dataTypeDescriptor.VersionKeyPropertyNames.Add(propertyName); + } + } + if (indexesElement != null) { dataTypeDescriptor.Indexes = indexesElement.Elements("Index").Select(DataTypeIndex.FromXml).ToList(); diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs index bfa26150d9..c68d265a0f 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs @@ -420,6 +420,7 @@ private void AlterStore(UpdateDataTypeDescriptor updateDataTypeDescriptor, DataT bool primaryKeyChanged = changeDescriptor.AddedKeyFields.Any() || changeDescriptor.DeletedKeyFields.Any() || changeDescriptor.KeyFieldsOrderChanged + || changeDescriptor.VersionKeyFieldsChanged || changeDescriptor.OriginalType.PrimaryKeyIsClusteredIndex != changeDescriptor.AlteredType.PrimaryKeyIsClusteredIndex; DropConstraints(originalTableName, primaryKeyChanged); From 55a1b86c1bac20d327d37c51c347fb57f7827867 Mon Sep 17 00:00:00 2001 From: Inna Boitsun Date: Wed, 7 Sep 2016 17:37:09 +0300 Subject: [PATCH 15/95] Fix Icons hover background --- Website/Composite/images/icons/svg/copy.svg | 6 +++--- .../images/icons/svg/page-list-unpublished-items.svg | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Website/Composite/images/icons/svg/copy.svg b/Website/Composite/images/icons/svg/copy.svg index 8ad353dadb..3ad0c2c134 100644 --- a/Website/Composite/images/icons/svg/copy.svg +++ b/Website/Composite/images/icons/svg/copy.svg @@ -2,9 +2,9 @@ - - - + + + diff --git a/Website/Composite/images/icons/svg/page-list-unpublished-items.svg b/Website/Composite/images/icons/svg/page-list-unpublished-items.svg index 5c9dd39b84..abe02f17eb 100644 --- a/Website/Composite/images/icons/svg/page-list-unpublished-items.svg +++ b/Website/Composite/images/icons/svg/page-list-unpublished-items.svg @@ -1,6 +1,4 @@  - - @@ -10,7 +8,7 @@ - + From 3416d9cc0d7c29fd4483b17968072641b228aeb2 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Thu, 8 Sep 2016 10:08:53 +0200 Subject: [PATCH 16/95] Tree definitions - fixing pre-filling of a parent element reference when adding new data items (#222) --- .../Trees/GenericAddDataActionNode.cs | 36 ++++++++++--------- .../Trees/PiggybagExtensionMethods.cs | 10 +++--- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Composite/C1Console/Trees/GenericAddDataActionNode.cs b/Composite/C1Console/Trees/GenericAddDataActionNode.cs index d624d02a9e..41d6e34e5f 100644 --- a/Composite/C1Console/Trees/GenericAddDataActionNode.cs +++ b/Composite/C1Console/Trees/GenericAddDataActionNode.cs @@ -4,11 +4,11 @@ using System.Linq; using System.Reflection; using System.Text; -using System.Xml.Linq; using Composite.C1Console.Elements; using Composite.C1Console.Security; using Composite.C1Console.Workflow; using Composite.Core.IO; +using Composite.Core.Linq; using Composite.Core.Serialization; using Composite.Core.Xml; using Composite.Data; @@ -30,24 +30,26 @@ public sealed class GenericAddDataActionNode : ActionNode // Cached - private List ParentIdEntrys { get; set; } + private List ParentIdEntries { get; set; } /// protected override void OnAddAction(Action actionAdder, EntityToken entityToken, TreeNodeDynamicContext dynamicContext, DynamicValuesHelperReplaceContext dynamicValuesHelperReplaceContext) { - StringBuilder payload = new StringBuilder(); + var payload = new StringBuilder(); this.Serialize(payload); - if (this.ParentIdEntrys.Count > 0) + if (this.ParentIdEntries.Count > 0) { List entityTokens = dynamicContext.Piggybag.GetParentEntityTokens().ToList(); - entityTokens.Reverse(); // Reversing the order so the latest partent will go first + entityTokens.Reverse(); entityTokens.Add(dynamicContext.CurrentEntityToken); entityTokens.Add(entityToken); - foreach (ParentIdEntry parentIdEntry in this.ParentIdEntrys) + entityTokens.Reverse(); + + foreach (ParentIdEntry parentIdEntry in this.ParentIdEntries) { DataEntityToken dataEntityToken = entityTokens.FindDataEntityToken(parentIdEntry.TargetInterface); if (dataEntityToken == null) continue; @@ -84,12 +86,12 @@ protected override void OnAddAction(Action actionAdder, EntityTok /// protected override void OnInitialize() { - if ((this.InterfaceType != null) && (typeof(IData).IsAssignableFrom(this.InterfaceType) == false)) + if (this.InterfaceType != null && !typeof(IData).IsAssignableFrom(this.InterfaceType)) { AddValidationError("TreeValidationError.Common.NotImplementingIData", this.InterfaceType, typeof(IData)); } - this.ParentIdEntrys = new List(); + this.ParentIdEntries = new List(); IEnumerable treeNodes = this.OwnerNode.Descendants(true).ToList(); foreach (TreeNode treeNode in treeNodes) @@ -98,8 +100,8 @@ protected override void OnInitialize() if (dataFilteringTreeNode == null) continue; - IEnumerable parentIdFilterNodes = dataFilteringTreeNode.FilterNodes.OfType(); - if (parentIdFilterNodes.Count() == 0) continue; + IEnumerable parentIdFilterNodes = dataFilteringTreeNode.FilterNodes.OfType().Evaluate(); + if (!parentIdFilterNodes.Any()) continue; foreach (ParentIdFilterNode parentIdFilterNode in parentIdFilterNodes) { @@ -109,32 +111,32 @@ protected override void OnInitialize() foreach (ForeignPropertyInfo foreignPropertyInfo in foreignPropertyInfos) { - ParentIdEntry parentIdEntry = new ParentIdEntry + var parentIdEntry = new ParentIdEntry { TargetInterface = interfaceType, TargetPropertyInfo = foreignPropertyInfo.TargetKeyPropertyInfo, SourcePropertyName = foreignPropertyInfo.SourcePropertyName }; - if (this.ParentIdEntrys.Contains(parentIdEntry) == false) + if (!this.ParentIdEntries.Contains(parentIdEntry)) { - this.ParentIdEntrys.Add(parentIdEntry); + this.ParentIdEntries.Add(parentIdEntry); } } } } - if (string.IsNullOrEmpty(this.CustomFormMarkupPath) == false) + if (!string.IsNullOrEmpty(this.CustomFormMarkupPath)) { try { string path = PathUtil.Resolve(this.CustomFormMarkupPath); - if (C1File.Exists(path) == false) + if (!C1File.Exists(path)) { AddValidationError("TreeValidationError.GenericAddDataAction.MissingMarkupFile", path); } - XDocument document = XDocumentUtils.Load(path); + XDocumentUtils.Load(path); this.CustomFormMarkupPath = path; } @@ -150,7 +152,7 @@ protected override void OnInitialize() /// public override string ToString() { - return string.Format("GenericAddDataActionNode, InterfaceType = {0}, Label = {1}", this.InterfaceType, this.Label); + return $"GenericAddDataActionNode, InterfaceType = {this.InterfaceType}, Label = {this.Label}"; } diff --git a/Composite/C1Console/Trees/PiggybagExtensionMethods.cs b/Composite/C1Console/Trees/PiggybagExtensionMethods.cs index 30927969ff..8ae7fa702c 100644 --- a/Composite/C1Console/Trees/PiggybagExtensionMethods.cs +++ b/Composite/C1Console/Trees/PiggybagExtensionMethods.cs @@ -80,10 +80,10 @@ public static bool TryGetPiggybaggedEntityToken(this Dictionary /// public static bool TryGetPiggybaggedEntityToken(this Dictionary piggybag, int generation, out EntityToken entityToken) { - string key = string.Format("{0}{1}", ParentEntityTokenPiggybagString, generation); + string key = $"{ParentEntityTokenPiggybagString}{generation}"; string serializedEntityToken; - if (piggybag.TryGetValue(key, out serializedEntityToken) == false) + if (!piggybag.TryGetValue(key, out serializedEntityToken)) { entityToken = null; return false; @@ -105,10 +105,10 @@ public static IEnumerable GetParentEntityTokens(this Dictionary Date: Thu, 8 Sep 2016 11:34:30 +0200 Subject: [PATCH 17/95] fix perspective change after data duplication --- .../C1Console/Actions/DuplicateActionToken.cs | 4 ++-- .../ConsoleCommandHelper.cs | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Composite/C1Console/Actions/DuplicateActionToken.cs b/Composite/C1Console/Actions/DuplicateActionToken.cs index 3ab6590d17..f535b9cf7d 100644 --- a/Composite/C1Console/Actions/DuplicateActionToken.cs +++ b/Composite/C1Console/Actions/DuplicateActionToken.cs @@ -63,9 +63,9 @@ public FlowToken Execute(string serializedEntityToken, string serializedActionTo var consoleId = flowControllerServicesContainer.GetService().CurrentConsoleId; - ConsoleCommandHelper.SelectConsoleElement(consoleId, newData.GetDataEntityToken()); + ConsoleCommandHelper.SelectConsoleElementWithoutPerspectiveChange(consoleId, newData.GetDataEntityToken()); - treeRefresher.PostRefreshMesseges(dataEntityToken); + treeRefresher.PostRefreshMessages(dataEntityToken); } return null; diff --git a/Composite/Plugins/Commands/ConsoleCommandHandlers/ConsoleCommandHelper.cs b/Composite/Plugins/Commands/ConsoleCommandHandlers/ConsoleCommandHelper.cs index 1c1fe13f09..2f91dbb16a 100644 --- a/Composite/Plugins/Commands/ConsoleCommandHandlers/ConsoleCommandHelper.cs +++ b/Composite/Plugins/Commands/ConsoleCommandHandlers/ConsoleCommandHelper.cs @@ -40,7 +40,24 @@ public static void SelectConsoleElement(string consoleId, EntityToken entityToke var selectItem = new SelectElementQueueItem { EntityToken = serializedEntityToken, - PerspectiveElementKey = perspectiveElementKey + //PerspectiveElementKey = perspectiveElementKey + }; + + ConsoleMessageQueueFacade.Enqueue(selectItem, consoleId); + } + + /// + /// Selects the specified element in the console, doesn't change the perspective + /// + /// The console id. + /// The entity token. + public static void SelectConsoleElementWithoutPerspectiveChange(string consoleId, EntityToken entityToken) + { + var serializedEntityToken = EntityTokenSerializer.Serialize(entityToken, true); + + var selectItem = new SelectElementQueueItem + { + EntityToken = serializedEntityToken, }; ConsoleMessageQueueFacade.Enqueue(selectItem, consoleId); From 9e3927245d2e74300ea9d3c255266d8e893d25ce Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Fri, 9 Sep 2016 13:02:12 +0200 Subject: [PATCH 18/95] Fixing previous change to DataTypeDescriptor; fixing compilation warnings --- Composite/AspNet/Razor/CompositeC1WebPage.cs | 1 + .../Forms/ITestAutomationLocatorInformation.cs | 10 +++------- .../C1Console/Workflow/FormsWorkflowExtensions.cs | 2 ++ .../UiControlLib/Foundation/ClientAttributes.cs | 2 ++ Composite/Data/Caching/CachingQueryable.cs | 5 ++--- Composite/Data/DynamicTypes/DataTypeDescriptor.cs | 2 +- .../GenericPublishProcessController.cs | 1 + 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Composite/AspNet/Razor/CompositeC1WebPage.cs b/Composite/AspNet/Razor/CompositeC1WebPage.cs index 0e468a38d8..1e8108ea8a 100644 --- a/Composite/AspNet/Razor/CompositeC1WebPage.cs +++ b/Composite/AspNet/Razor/CompositeC1WebPage.cs @@ -135,6 +135,7 @@ private FunctionContextContainer GetFunctionContext() return PageData[RazorHelper.PageContext_FunctionContextContainer]; } + /// public override void ExecutePageHierarchy() { base.ExecutePageHierarchy(); diff --git a/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs b/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs index 22575d285a..8a1969d169 100644 --- a/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs +++ b/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Composite.C1Console.Forms +namespace Composite.C1Console.Forms { + /// public interface ITestAutomationLocatorInformation { + /// string TestAutomationLocator { get; } } } diff --git a/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs b/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs index 6852e1f13b..a2cded1ad7 100644 --- a/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs +++ b/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs @@ -2,10 +2,12 @@ namespace Composite.C1Console.Workflow { + /// public static class FormsWorkflowExtensions { private static readonly List _extensions = new List(); + /// public static void Register(IFormsWorkflowExtension extension) => _extensions.Add(extension); internal static ICollection GetExtensions() => _extensions; diff --git a/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs b/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs index 95b5704281..550097d36a 100644 --- a/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs +++ b/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs @@ -3,6 +3,7 @@ namespace Composite.Core.WebClient.UiControlLib.Foundation { + /// public static class ClientAttributes { internal static void WriteClientAttributes(this WebControl uiControl, HtmlTextWriter writer) @@ -31,6 +32,7 @@ internal static void AddClientAttributes(this WebControl uiControl, HtmlTextWrit } } + /// public static void CopyClientAttributesTo(this UserControl uiControl, WebControl targetControl) { foreach (string attributeName in uiControl.Attributes.Keys) diff --git a/Composite/Data/Caching/CachingQueryable.cs b/Composite/Data/Caching/CachingQueryable.cs index 56b64655a4..8f94fba8c6 100644 --- a/Composite/Data/Caching/CachingQueryable.cs +++ b/Composite/Data/Caching/CachingQueryable.cs @@ -7,7 +7,6 @@ using Composite.Core.Types; using Composite.Data.Caching.Foundation; using System.Reflection; -using Composite.Core.Extensions; using Composite.Core.Linq; using Composite.Data.Foundation; @@ -78,9 +77,9 @@ static CachingQueryable() } } - private static IEnumerable WrapData(IEnumerable input) where T : class, IData + private static IEnumerable WrapData(IEnumerable input) where TData : class, IData { - return input.Select(DataWrappingFacade.Wrap); + return input.Select(DataWrappingFacade.Wrap); } public CachingQueryable(DataCachingFacade.CachedTable cachedTable, Func originalQueryGetter) diff --git a/Composite/Data/DynamicTypes/DataTypeDescriptor.cs b/Composite/Data/DynamicTypes/DataTypeDescriptor.cs index f08d15761c..aafdf08ba3 100644 --- a/Composite/Data/DynamicTypes/DataTypeDescriptor.cs +++ b/Composite/Data/DynamicTypes/DataTypeDescriptor.cs @@ -753,7 +753,7 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField if (versionKeyPropertyNamesElement != null) { - foreach (XElement elm in keyPropertyNamesElement.Elements("VersionKeyPropertyName")) + foreach (XElement elm in versionKeyPropertyNamesElement.Elements("VersionKeyPropertyName")) { var propertyName = elm.GetRequiredAttributeValue("name"); diff --git a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs index c72f2dd4f3..a95431fcf2 100644 --- a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs +++ b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs @@ -42,6 +42,7 @@ public sealed class GenericPublishProcessController : IPublishProcessController /// public const string Published = "published"; + /// public static string BulkPublishingCommandsTag { get; } = "BulkPublishingCommands"; private static readonly string _backToAwaitingApproval = "awaitingApprovalBack"; From b3ce5834a362181a41cf1497d266e60854624b9c Mon Sep 17 00:00:00 2001 From: Melanie Bergeron Date: Fri, 9 Sep 2016 09:28:03 -0400 Subject: [PATCH 19/95] localization Tool commit --- .../Composite.Management.en-us.xml | 1246 ++++++++--------- 1 file changed, 618 insertions(+), 628 deletions(-) diff --git a/Website/Composite/localization/Composite.Management.en-us.xml b/Website/Composite/localization/Composite.Management.en-us.xml index a505c1e26d..55c369e0d2 100644 --- a/Website/Composite/localization/Composite.Management.en-us.xml +++ b/Website/Composite/localization/Composite.Management.en-us.xml @@ -1,295 +1,292 @@  - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + - - - - + + + + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + - - + + @@ -297,327 +294,326 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -628,75 +624,69 @@ - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + \ No newline at end of file From 6de0053eb6df2568da5ad2ff1c2cb9d6b4e8d8ea Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Tue, 13 Sep 2016 11:33:14 +0200 Subject: [PATCH 20/95] Fixing a nightwatch test --- Website/test/e2e/suite/000_setup/installSite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website/test/e2e/suite/000_setup/installSite.js b/Website/test/e2e/suite/000_setup/installSite.js index 7074c173ba..589fe34033 100644 --- a/Website/test/e2e/suite/000_setup/installSite.js +++ b/Website/test/e2e/suite/000_setup/installSite.js @@ -17,7 +17,7 @@ module.exports = { beforeEach: function (browser) { // 1 Launch an uninitialized website. browser - .url(browser.launchUrl + '/Composite/top.aspx?mode=develop') + .url(browser.launchUrl + '/Composite/top.aspx') .waitForElementVisible('.welcomepage', 10000); }, 'install Venus starter site': function (browser) { From 04df58fa532a801241d9fe6519265ad89ee31d41 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Tue, 13 Sep 2016 13:23:47 +0200 Subject: [PATCH 21/95] Attempting to fix NightWatch run during build --- nightwatch.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nightwatch.json b/nightwatch.json index 9dbcffb7cb..8de595b3af 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -36,7 +36,10 @@ "browserName": "chrome", "loggingPrefs": { "browser": "ALL" } , "javascriptEnabled": true, - "acceptSslCerts": true + "acceptSslCerts": true, + "chromeOptions" : { + "args" : ["--no-sandbox"] + } } }, From 1d7190c49df95173486b38534702e623cae19c6e Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Tue, 13 Sep 2016 13:48:35 +0200 Subject: [PATCH 22/95] Properly logging exceptions related to invalid xml markup referenced in tree definitions, refactoring --- Composite/C1Console/Trees/ActionNode.cs | 46 +++++++++++++++++-- .../Trees/GenericAddDataActionNode.cs | 46 +++++++------------ .../Trees/GenericEditDataActionNode.cs | 28 ++--------- .../Foundation/ClientAttributes.cs | 1 - .../Composite.C1Console.Trees.en-us.xml | 9 ++-- 5 files changed, 68 insertions(+), 62 deletions(-) diff --git a/Composite/C1Console/Trees/ActionNode.cs b/Composite/C1Console/Trees/ActionNode.cs index 3487d87e04..2c5d6d10fb 100644 --- a/Composite/C1Console/Trees/ActionNode.cs +++ b/Composite/C1Console/Trees/ActionNode.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; using System.Text; -using Composite.Data; +using System.Xml; +using System.Xml.Linq; using Composite.C1Console.Elements; using Composite.Core.ResourceSystem; using Composite.C1Console.Security; +using Composite.Core; +using Composite.Core.IO; using Composite.Core.Serialization; @@ -146,9 +149,8 @@ public static ActionNode Deserialize(Dictionary serializedValueC } Tree tree = TreeFacade.GetTree(treeId); - if (tree == null) return null; - return tree.GetActionNode(actionNodeId); + return tree?.GetActionNode(actionNodeId); } @@ -166,5 +168,41 @@ protected void AddValidationError(string stringName, params object[] args) { this.OwnerNode.Tree.BuildResult.AddValidationError(ValidationError.Create(this.XPath, stringName, args)); } - } + + + internal string LoadAndValidateCustomFormMarkupPath(string customFormMarkupPath) + { + string path; + + try + { + path = PathUtil.Resolve(customFormMarkupPath); + if (!C1File.Exists(path)) + { + AddValidationError("TreeValidationError.CustomFormMarkup.MissingFile", path); + return customFormMarkupPath; + } + } + catch + { + AddValidationError("TreeValidationError.CustomFormMarkup.BadMarkupPath", customFormMarkupPath); + return customFormMarkupPath; + } + + + try + { + XDocument.Load(path); + } + catch(Exception ex) + { + Log.LogError(nameof(ActionNode), $"Failed to load xml file '{path}'"); + Log.LogError(nameof(ActionNode), ex); + + AddValidationError("TreeValidationError.CustomFormMarkup.InvalidXml", customFormMarkupPath); + } + + return path; + } + } } diff --git a/Composite/C1Console/Trees/GenericAddDataActionNode.cs b/Composite/C1Console/Trees/GenericAddDataActionNode.cs index 41d6e34e5f..4db020e742 100644 --- a/Composite/C1Console/Trees/GenericAddDataActionNode.cs +++ b/Composite/C1Console/Trees/GenericAddDataActionNode.cs @@ -7,10 +7,8 @@ using Composite.C1Console.Elements; using Composite.C1Console.Security; using Composite.C1Console.Workflow; -using Composite.Core.IO; using Composite.Core.Linq; using Composite.Core.Serialization; -using Composite.Core.Xml; using Composite.Data; @@ -111,12 +109,11 @@ protected override void OnInitialize() foreach (ForeignPropertyInfo foreignPropertyInfo in foreignPropertyInfos) { - var parentIdEntry = new ParentIdEntry - { - TargetInterface = interfaceType, - TargetPropertyInfo = foreignPropertyInfo.TargetKeyPropertyInfo, - SourcePropertyName = foreignPropertyInfo.SourcePropertyName - }; + var parentIdEntry = new ParentIdEntry( + interfaceType, + foreignPropertyInfo.TargetKeyPropertyInfo, + foreignPropertyInfo.SourcePropertyName + ); if (!this.ParentIdEntries.Contains(parentIdEntry)) { @@ -128,27 +125,11 @@ protected override void OnInitialize() if (!string.IsNullOrEmpty(this.CustomFormMarkupPath)) { - try - { - string path = PathUtil.Resolve(this.CustomFormMarkupPath); - if (!C1File.Exists(path)) - { - AddValidationError("TreeValidationError.GenericAddDataAction.MissingMarkupFile", path); - } - - XDocumentUtils.Load(path); - - this.CustomFormMarkupPath = path; - } - catch - { - AddValidationError("TreeValidationError.GenericAddDataAction.BadMarkupPath", this.CustomFormMarkupPath); - } + this.CustomFormMarkupPath = LoadAndValidateCustomFormMarkupPath(CustomFormMarkupPath); } } - /// public override string ToString() { @@ -160,16 +141,23 @@ public override string ToString() [DebuggerDisplay("{SourcePropertyName} -> {TargetInterface}")] private sealed class ParentIdEntry { - public Type TargetInterface { get; set; } - public PropertyInfo TargetPropertyInfo { get; set; } - public string SourcePropertyName { get; set; } + public ParentIdEntry(Type targetInterface, PropertyInfo targetPropertyInfo, string sourcePropertyName) + { + TargetInterface = targetInterface; + TargetPropertyInfo = targetPropertyInfo; + SourcePropertyName = sourcePropertyName; + } + + public Type TargetInterface { get; } + public PropertyInfo TargetPropertyInfo { get; } + public string SourcePropertyName { get; } public override bool Equals(object obj) { return Equals(obj as ParentIdEntry); } - public bool Equals(ParentIdEntry parentIdEntry) + private bool Equals(ParentIdEntry parentIdEntry) { if (parentIdEntry == null) return false; diff --git a/Composite/C1Console/Trees/GenericEditDataActionNode.cs b/Composite/C1Console/Trees/GenericEditDataActionNode.cs index 34a08bf681..0d14e0be3b 100644 --- a/Composite/C1Console/Trees/GenericEditDataActionNode.cs +++ b/Composite/C1Console/Trees/GenericEditDataActionNode.cs @@ -1,12 +1,9 @@ using System; using System.Text; -using System.Xml.Linq; using Composite.C1Console.Elements; using Composite.C1Console.Security; using Composite.C1Console.Workflow; -using Composite.Core.IO; using Composite.Core.Serialization; -using Composite.Core.Xml; namespace Composite.C1Console.Trees @@ -24,7 +21,7 @@ public sealed class GenericEditDataActionNode : ActionNode /// protected override void OnAddAction(Action actionAdder, EntityToken entityToken, TreeNodeDynamicContext dynamicContext, DynamicValuesHelperReplaceContext dynamicValuesHelperReplaceContext) { - StringBuilder payload = new StringBuilder(); + var payload = new StringBuilder(); this.Serialize(payload); StringConversionServices.SerializeKeyValuePair(payload, "_IconResourceName_", Icon.ResourceName); @@ -47,29 +44,14 @@ protected override void OnAddAction(Action actionAdder, EntityTok /// protected override void OnInitialize() { - if ((this.OwnerNode is DataElementsTreeNode) == false) + if (!(this.OwnerNode is DataElementsTreeNode)) { AddValidationError("TreeValidationError.GenericEditDataAction.OwnerIsNotDataNode"); } - if (string.IsNullOrEmpty(this.CustomFormMarkupPath) == false) + if (!string.IsNullOrEmpty(this.CustomFormMarkupPath)) { - try - { - string path = PathUtil.Resolve(this.CustomFormMarkupPath); - if (C1File.Exists(path) == false) - { - AddValidationError("TreeValidationError.GenericEditDataAction.MissingMarkupFile", path); - } - - XDocument document = XDocumentUtils.Load(path); - - this.CustomFormMarkupPath = path; - } - catch - { - AddValidationError("TreeValidationError.GenericEditDataAction.BadMarkupPath", this.CustomFormMarkupPath); - } + this.CustomFormMarkupPath = LoadAndValidateCustomFormMarkupPath(CustomFormMarkupPath); } } @@ -78,7 +60,7 @@ protected override void OnInitialize() /// public override string ToString() { - return string.Format("GenericEditDataActionNode, Label = {0}", this.Label); + return $"GenericEditDataActionNode, Label = {this.Label}"; } } } diff --git a/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs b/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs index 550097d36a..fe68c7a648 100644 --- a/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs +++ b/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs @@ -40,7 +40,6 @@ public static void CopyClientAttributesTo(this UserControl uiControl, WebControl string attributeNameLower = attributeName.ToLowerInvariant(); if (attributeNameLower.StartsWith("client_")) { - string clientAttributeName = attributeNameLower.Substring("client_".Length); targetControl.Attributes[attributeName] = uiControl.Attributes[attributeName]; } } diff --git a/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml b/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml index 66d9afe4d7..020482c2a5 100644 --- a/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml +++ b/Website/Composite/localization/Composite.C1Console.Trees.en-us.xml @@ -56,13 +56,12 @@ - + + + + - - - - From 2f1ba9c8b8d8c3ab6a37085102a2e6848fb7db17 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Tue, 13 Sep 2016 14:30:11 +0200 Subject: [PATCH 23/95] Nightwatch - removing "devMode" test, as development mode isn't available in a release build --- Website/test/e2e/suite/100_login/devMode.js | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 Website/test/e2e/suite/100_login/devMode.js diff --git a/Website/test/e2e/suite/100_login/devMode.js b/Website/test/e2e/suite/100_login/devMode.js deleted file mode 100644 index 005868fce6..0000000000 --- a/Website/test/e2e/suite/100_login/devMode.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - 'Development mode has prefilled credentials': function (browser) { - browser.url(browser.launchUrl + '/Composite/top.aspx?mode=develop'); - login = browser.page.login(); - login.assert.value('@usernameInput', 'admin'); - login.assert.value('@passwordInput', '123456'); - } -}; From 5c47ac023eb2fc2e2cae1c27f2d35fcdfe75c20e Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 14 Sep 2016 12:25:15 +0200 Subject: [PATCH 24/95] make string field of added meta type in debug mode nullable --- Composite/Data/DynamicTypes/Debug/DynamicTempTypeCreator.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Composite/Data/DynamicTypes/Debug/DynamicTempTypeCreator.cs b/Composite/Data/DynamicTypes/Debug/DynamicTempTypeCreator.cs index 9d6374643b..fbdd615b3d 100644 --- a/Composite/Data/DynamicTypes/Debug/DynamicTempTypeCreator.cs +++ b/Composite/Data/DynamicTypes/Debug/DynamicTempTypeCreator.cs @@ -90,6 +90,12 @@ private void Initialize() new DataFieldDescriptor(Guid.NewGuid(), "MyStringField", StoreFieldType.String(64), typeof(string)) { Position = 10, + IsNullable = true, + DataUrlProfile = new DataUrlProfile() + { + Format = DataUrlSegmentFormat.DateTime_Year, + Order = 1 + }, FormRenderingProfile = new DataFieldFormRenderingProfile { Label = "MyStringField", From 6e138ff2b791eb40fb97835e076e78b169f02daa Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 14 Sep 2016 12:26:43 +0200 Subject: [PATCH 25/95] make data-qa attribute of stages "perspective+Label" to be identified during e2e tests --- .../source/top/ui/bindings/stage/decks/StageDecksBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website/Composite/scripts/source/top/ui/bindings/stage/decks/StageDecksBinding.js b/Website/Composite/scripts/source/top/ui/bindings/stage/decks/StageDecksBinding.js index 3a4b1021df..f37537060b 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/stage/decks/StageDecksBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/stage/decks/StageDecksBinding.js @@ -49,7 +49,7 @@ StageDecksBinding.prototype.mountDefinition = function ( definition ) { deckBinding.perspectiveNode = definition.node; deckBinding.definition = definition; if (Application.isTestEnvironment) { - deckBinding.setProperty("data-qa", "perspective" + definition.node.getTag()); + deckBinding.setProperty("data-qa", "perspective" + definition.label); } this._decks [ deckBinding.handle ] = deckBinding; this.add ( deckBinding ); From 81a90413f8f9ee17516b420ebf603ff157071712 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 14 Sep 2016 12:28:47 +0200 Subject: [PATCH 26/95] introducing new api for higher level test scripts --- .../e2e/commands/assertBrowserContains.js | 16 +++ .../assertBrowserContainsAttribute.js | 16 +++ Website/test/e2e/commands/assertFieldValue.js | 27 ++++ .../e2e/commands/assertTreeNodeHasChild.js | 16 +++ .../e2e/commands/assertTreeNodeIsEmpty.js | 16 +++ .../e2e/commands/assertTreeNodeIsNotEmpty.js | 16 +++ .../test/e2e/commands/clickDataBySibilings.js | 17 +++ .../test/e2e/commands/clickDialogButton.js | 18 +++ Website/test/e2e/commands/clickLabel.js | 25 ++++ Website/test/e2e/commands/clickSave.js | 16 +++ Website/test/e2e/commands/clickText.js | 17 +++ Website/test/e2e/commands/closeDocumentTab.js | 17 +++ Website/test/e2e/commands/openTreeNode.js | 15 +++ .../e2e/commands/replaceTextInCodeMirror.js | 23 ++++ .../test/e2e/commands/rightClickSelector.js | 25 ++++ .../e2e/commands/selectActionFromToolbar.js | 19 +++ Website/test/e2e/commands/selectContentTab.js | 16 +++ Website/test/e2e/commands/selectDialog.js | 16 +++ .../test/e2e/commands/selectDocumentTab.js | 16 +++ .../test/e2e/commands/selectFrameWithXpath.js | 119 ++++++++++++++++++ .../test/e2e/commands/selectPerspective.js | 15 +++ .../test/e2e/commands/selectTreeNodeAction.js | 20 +++ Website/test/e2e/commands/setFieldValue.js | 22 ++++ .../e2e/commands/setFieldValueInFieldGroup.js | 24 ++++ Website/test/e2e/commands/switchContentTab.js | 15 +++ Website/test/e2e/pageObjects/appWindow.js | 1 + Website/test/e2e/pageObjects/content.js | 36 ++++-- Website/test/e2e/pageObjects/editor.js | 61 ++++++--- Website/test/e2e/pageObjects/systemView.js | 64 ++++++++-- 29 files changed, 686 insertions(+), 38 deletions(-) create mode 100644 Website/test/e2e/commands/assertBrowserContains.js create mode 100644 Website/test/e2e/commands/assertBrowserContainsAttribute.js create mode 100644 Website/test/e2e/commands/assertFieldValue.js create mode 100644 Website/test/e2e/commands/assertTreeNodeHasChild.js create mode 100644 Website/test/e2e/commands/assertTreeNodeIsEmpty.js create mode 100644 Website/test/e2e/commands/assertTreeNodeIsNotEmpty.js create mode 100644 Website/test/e2e/commands/clickDataBySibilings.js create mode 100644 Website/test/e2e/commands/clickDialogButton.js create mode 100644 Website/test/e2e/commands/clickLabel.js create mode 100644 Website/test/e2e/commands/clickSave.js create mode 100644 Website/test/e2e/commands/clickText.js create mode 100644 Website/test/e2e/commands/closeDocumentTab.js create mode 100644 Website/test/e2e/commands/openTreeNode.js create mode 100644 Website/test/e2e/commands/replaceTextInCodeMirror.js create mode 100644 Website/test/e2e/commands/rightClickSelector.js create mode 100644 Website/test/e2e/commands/selectActionFromToolbar.js create mode 100644 Website/test/e2e/commands/selectContentTab.js create mode 100644 Website/test/e2e/commands/selectDialog.js create mode 100644 Website/test/e2e/commands/selectDocumentTab.js create mode 100644 Website/test/e2e/commands/selectFrameWithXpath.js create mode 100644 Website/test/e2e/commands/selectPerspective.js create mode 100644 Website/test/e2e/commands/selectTreeNodeAction.js create mode 100644 Website/test/e2e/commands/setFieldValue.js create mode 100644 Website/test/e2e/commands/setFieldValueInFieldGroup.js create mode 100644 Website/test/e2e/commands/switchContentTab.js diff --git a/Website/test/e2e/commands/assertBrowserContains.js b/Website/test/e2e/commands/assertBrowserContains.js new file mode 100644 index 0000000000..c508a3f252 --- /dev/null +++ b/Website/test/e2e/commands/assertBrowserContains.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertBrowserContains() { + events.EventEmitter.call(this); +} + +AssertBrowserContains.prototype.command = function (selector, value) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective(); + content._assertBrowserContains(selector, value); + return this.client.api; +}; + +module.exports = AssertBrowserContains; diff --git a/Website/test/e2e/commands/assertBrowserContainsAttribute.js b/Website/test/e2e/commands/assertBrowserContainsAttribute.js new file mode 100644 index 0000000000..720366a55a --- /dev/null +++ b/Website/test/e2e/commands/assertBrowserContainsAttribute.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertBrowserContainsAttribute() { + events.EventEmitter.call(this); +} + +AssertBrowserContainsAttribute.prototype.command = function (selector,attribute, value) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective(); + content._assertBrowserContainsAttribute(selector,attribute, value); + return this.client.api; +}; + +module.exports = AssertBrowserContainsAttribute; diff --git a/Website/test/e2e/commands/assertFieldValue.js b/Website/test/e2e/commands/assertFieldValue.js new file mode 100644 index 0000000000..d3f63af510 --- /dev/null +++ b/Website/test/e2e/commands/assertFieldValue.js @@ -0,0 +1,27 @@ +var events = require('events'); + +function AssertFieldValue() { + events.EventEmitter.call(this); +} + +AssertFieldValue.prototype.command = function (dialogLabel,fieldLabel,vlaueToAssert,inputType) { + if(inputType == null){ + inputType = "input"; + } + if (dialogLabel == null) { + this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); + } else { + this.client.api.selectFrameWithXpath('//*[local-name() = "fieldgroup"][@label="' + dialogLabel + '"]'); + } + this.client.api + .useXpath() + .getValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]',function(result) { + this.assert.equal(typeof result, "object"); + this.assert.equal(result.status, 0); + this.assert.equal(result.value, vlaueToAssert); + }).useCss(); + + return this.client.api; +}; + +module.exports = AssertFieldValue; diff --git a/Website/test/e2e/commands/assertTreeNodeHasChild.js b/Website/test/e2e/commands/assertTreeNodeHasChild.js new file mode 100644 index 0000000000..2b19515eb2 --- /dev/null +++ b/Website/test/e2e/commands/assertTreeNodeHasChild.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertTreeNodeHasChild() { + events.EventEmitter.call(this); +} + +AssertTreeNodeHasChild.prototype.command = function (parentLabel, childLabel) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective() + ._assertTreeNodeHasChild(parentLabel, childLabel); + return this.client.api; +}; + +module.exports = AssertTreeNodeHasChild; diff --git a/Website/test/e2e/commands/assertTreeNodeIsEmpty.js b/Website/test/e2e/commands/assertTreeNodeIsEmpty.js new file mode 100644 index 0000000000..9ea8177d1f --- /dev/null +++ b/Website/test/e2e/commands/assertTreeNodeIsEmpty.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertTreeNodeIsEmpty() { + events.EventEmitter.call(this); +} + +AssertTreeNodeIsEmpty.prototype.command = function (parentLabel, childLabel) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective() + ._assertTreeNodeIsEmpty(parentLabel, childLabel); + return this.client.api; +}; + +module.exports = AssertTreeNodeIsEmpty; diff --git a/Website/test/e2e/commands/assertTreeNodeIsNotEmpty.js b/Website/test/e2e/commands/assertTreeNodeIsNotEmpty.js new file mode 100644 index 0000000000..8e3f720d78 --- /dev/null +++ b/Website/test/e2e/commands/assertTreeNodeIsNotEmpty.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertTreeNodeIsNotEmpty() { + events.EventEmitter.call(this); +} + +AssertTreeNodeIsNotEmpty.prototype.command = function (parentLabel, childLabel) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective() + ._assertTreeNodeIsNotEmpty(parentLabel, childLabel); + return this.client.api; +}; + +module.exports = AssertTreeNodeIsNotEmpty; diff --git a/Website/test/e2e/commands/clickDataBySibilings.js b/Website/test/e2e/commands/clickDataBySibilings.js new file mode 100644 index 0000000000..91ffbfda3c --- /dev/null +++ b/Website/test/e2e/commands/clickDataBySibilings.js @@ -0,0 +1,17 @@ +var events = require('events'); + +function ClickDataBySibiling() { + events.EventEmitter.call(this); +} + +ClickDataBySibiling.prototype.command = function (vlaue) { + this.client.api.selectFrameWithXpath('//*[local-name()="fielddesc"][text()="'+vlaue+'"]/..//*[local-name()="fielddata"]'); + + this.client.api + .useXpath() + .click('//*[local-name()="fielddesc"][text()="'+vlaue+'"]/..//*[local-name()="fielddata"]').useCss() + + return this.client.api; +}; + +module.exports = ClickDataBySibiling; \ No newline at end of file diff --git a/Website/test/e2e/commands/clickDialogButton.js b/Website/test/e2e/commands/clickDialogButton.js new file mode 100644 index 0000000000..344f826ce4 --- /dev/null +++ b/Website/test/e2e/commands/clickDialogButton.js @@ -0,0 +1,18 @@ +var events = require('events'); +var util = require('util'); + +function ClickOnDialogButton() { + events.EventEmitter.call(this); +} + +util.inherits(ClickOnDialogButton, events.EventEmitter); + +ClickOnDialogButton.prototype.command = function (button) { + this.client.api + .selectFrame('#dialogbuttonstoolbar') + .waitForElementVisible('clickbutton[label="' + button + '"]', 1000) + .click('clickbutton[label="'+button+'"]', () => this.emit('complete')) + return this.client.api; +}; + +module.exports = ClickOnDialogButton; diff --git a/Website/test/e2e/commands/clickLabel.js b/Website/test/e2e/commands/clickLabel.js new file mode 100644 index 0000000000..64f517cd00 --- /dev/null +++ b/Website/test/e2e/commands/clickLabel.js @@ -0,0 +1,25 @@ +var events = require('events'); + +function ClickLabel() { + events.EventEmitter.call(this); +} + +ClickLabel.prototype.command = function (label,parentLabel) { + var selector; + if(parentLabel===null){ + selector ='//*[@label="'+label+'"]'; + } + else{ + selector= '//*[@label="'+parentLabel+'"]//*[@label="'+label+'"]' + } + this.client.api.selectFrameWithXpath('//*[@label="'+label+'"]'); + + this.client.api + .useXpath() + .moveToElement('//*[@label="'+label+'"]',null,null) + .mouseButtonClick('left').useCss() + + return this.client.api; +}; + +module.exports = ClickLabel; \ No newline at end of file diff --git a/Website/test/e2e/commands/clickSave.js b/Website/test/e2e/commands/clickSave.js new file mode 100644 index 0000000000..c93a0380d3 --- /dev/null +++ b/Website/test/e2e/commands/clickSave.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function ClickSave() { + events.EventEmitter.call(this); +} + +ClickSave.prototype.command = function () { + this.client.api + .selectFrame('#savebutton'); + this.client.api.expect.element('#savebutton').to.not.have.attribute('isdisabled'); + this.client.api.click('#savebutton > labelbox'); + this.client.api.waitForElementVisible('#savebutton[isdisabled="true"]',20000); + return this.client.api; +}; + +module.exports = ClickSave; \ No newline at end of file diff --git a/Website/test/e2e/commands/clickText.js b/Website/test/e2e/commands/clickText.js new file mode 100644 index 0000000000..a42fdc52da --- /dev/null +++ b/Website/test/e2e/commands/clickText.js @@ -0,0 +1,17 @@ +var events = require('events'); + +function ClickText() { + events.EventEmitter.call(this); +} + +ClickText.prototype.command = function (vlaue) { + this.client.api.selectFrameWithXpath('//*[text()="'+vlaue+'"]'); + + this.client.api + .useXpath() + .click('//*[text()="'+vlaue+'"]').useCss() + + return this.client.api; +}; + +module.exports = ClickText; \ No newline at end of file diff --git a/Website/test/e2e/commands/closeDocumentTab.js b/Website/test/e2e/commands/closeDocumentTab.js new file mode 100644 index 0000000000..5b8899ebcf --- /dev/null +++ b/Website/test/e2e/commands/closeDocumentTab.js @@ -0,0 +1,17 @@ +var events = require('events'); + +function CloseDocumentTab() { + events.EventEmitter.call(this); +} + +CloseDocumentTab.prototype.command = function (tabName) { + + this.client.api.selectFrameWithXpath('//*[local-name() = "docktab"]//*[@label="'+tabName+'"]'); + this.client.api + .useXpath() + .click('//*[local-name() = "docktab"]//*[@label="'+tabName+'"]/*//*[local-name() = "control"][@controltype="close"]').useCss() + + return this.client.api; +}; + +module.exports = CloseDocumentTab; \ No newline at end of file diff --git a/Website/test/e2e/commands/openTreeNode.js b/Website/test/e2e/commands/openTreeNode.js new file mode 100644 index 0000000000..7ab47c82f0 --- /dev/null +++ b/Website/test/e2e/commands/openTreeNode.js @@ -0,0 +1,15 @@ +var events = require('events'); + +function OpenNode() { + events.EventEmitter.call(this); +} + +OpenNode.prototype.command = function (parentLabel,childLabel) { + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective() + ._openTreeNode(parentLabel,childLabel); + return this.client.api; +}; + +module.exports = OpenNode; diff --git a/Website/test/e2e/commands/replaceTextInCodeMirror.js b/Website/test/e2e/commands/replaceTextInCodeMirror.js new file mode 100644 index 0000000000..f04cfa919d --- /dev/null +++ b/Website/test/e2e/commands/replaceTextInCodeMirror.js @@ -0,0 +1,23 @@ +var util = require('util'); +var events = require('events'); + +function ReplaceTextCodeMirror() { + events.EventEmitter.call(this); +} + +ReplaceTextCodeMirror.prototype.command = function (oldVlaue,newValue) { + this.client.api.selectFrameWithXpath('//*[@id="textarea"]'); + + this.client.api.click('#textarea') + this.client.api.execute(function(oldVlaue,newValue) { + + var editor = document.getElementsByClassName('CodeMirror')[0].CodeMirror; + var text = editor.getValue(); + editor.setValue(text.replace(oldVlaue,newValue)); + + }, [oldVlaue,newValue]); + return this.client.api; + +}; + +module.exports = ReplaceTextCodeMirror; \ No newline at end of file diff --git a/Website/test/e2e/commands/rightClickSelector.js b/Website/test/e2e/commands/rightClickSelector.js new file mode 100644 index 0000000000..03545bc6cd --- /dev/null +++ b/Website/test/e2e/commands/rightClickSelector.js @@ -0,0 +1,25 @@ +var util = require('util'); +var events = require('events'); + +function RightClick() { + events.EventEmitter.call(this); +} + +util.inherits(RightClick, events.EventEmitter); + +RightClick.prototype.command = function (selector) { + this.client.api.element('css selector', selector, result => { + if (!result.value.ELEMENT) { + this.client.assertion(false, null, null, 'Element <' + selector + '> was not found', this.abortOnFailure, this._stackTrace); + this.emit('complete'); + return; + } + var element = result.value.ELEMENT; + this.client.api.moveTo(element, null, null, () => { + this.client.api.mouseButtonClick('right',() => this.emit('complete')); + }); + }); + return this.client.api; +}; + +module.exports = RightClick; diff --git a/Website/test/e2e/commands/selectActionFromToolbar.js b/Website/test/e2e/commands/selectActionFromToolbar.js new file mode 100644 index 0000000000..e4f7392dd7 --- /dev/null +++ b/Website/test/e2e/commands/selectActionFromToolbar.js @@ -0,0 +1,19 @@ +var events = require('events'); + +function SelectActionFromToolbar() { + events.EventEmitter.call(this); +} + +SelectActionFromToolbar.prototype.command = function (perspective,node,action) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enter(perspective) + ._selectTreeNode(node) + .leaveFrame() + content + .click('toolbarbutton[label="'+action+'"]') + return this.client.api; +}; + +module.exports = SelectActionFromToolbar; diff --git a/Website/test/e2e/commands/selectContentTab.js b/Website/test/e2e/commands/selectContentTab.js new file mode 100644 index 0000000000..2e10ac2bed --- /dev/null +++ b/Website/test/e2e/commands/selectContentTab.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function SelectContentTab() { + events.EventEmitter.call(this); +} + +SelectContentTab.prototype.command = function (tabName) { + this.client.api.selectFrameWithXpath('//*[local-name() = "tabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]'); + this.client.api + .useXpath() + .click('//*[local-name() = "tabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]').useCss() + + return this.client.api; +}; + +module.exports = SelectContentTab; \ No newline at end of file diff --git a/Website/test/e2e/commands/selectDialog.js b/Website/test/e2e/commands/selectDialog.js new file mode 100644 index 0000000000..ebe89941ab --- /dev/null +++ b/Website/test/e2e/commands/selectDialog.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function SelectDialog() { + events.EventEmitter.call(this); +} + +SelectDialog.prototype.command = function (tabName) { + this.client.api.selectFrameWithXpath('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]'); + this.client.api + .useXpath() + .click('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]').useCss() + + return this.client.api; +}; + +module.exports = SelectDialog; \ No newline at end of file diff --git a/Website/test/e2e/commands/selectDocumentTab.js b/Website/test/e2e/commands/selectDocumentTab.js new file mode 100644 index 0000000000..72aaa752bb --- /dev/null +++ b/Website/test/e2e/commands/selectDocumentTab.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function SelectDocumentTab() { + events.EventEmitter.call(this); +} + +SelectDocumentTab.prototype.command = function (tabName) { + this.client.api.selectFrameWithXpath('//*[local-name() = "docktabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]'); + this.client.api + .useXpath() + .click('//*[local-name() = "docktabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]').useCss(); + + return this.client.api; +}; + +module.exports = SelectDocumentTab; \ No newline at end of file diff --git a/Website/test/e2e/commands/selectFrameWithXpath.js b/Website/test/e2e/commands/selectFrameWithXpath.js new file mode 100644 index 0000000000..3944baa5e2 --- /dev/null +++ b/Website/test/e2e/commands/selectFrameWithXpath.js @@ -0,0 +1,119 @@ +var util = require('util'); +var events = require('events'); + +function SelectFrameWithXpath() { + events.EventEmitter.call(this); +} + +util.inherits(SelectFrameWithXpath, events.EventEmitter); + +function elementPresentPromise(client, selector) { + return new Promise(resolve => { + client.element('xpath', selector, result => { + if (result.error) { + resolve(false); + } else { + resolve(true); + } + }); + }); +} + +function elementListPromise(client, selector) { + return new Promise((resolve, reject) => { + client.elements('css selector', selector, result => { + if (result.error) { + reject(result.error); + } else { + resolve(result.value); + } + }); + }); +} + +function framePromise(client, element) { + return new Promise((resolve, reject) => { + client.frame(element, result => { + if (result.error) { + reject(result.error); + } else { + resolve(); + } + }); + }); +} + +function frameParentPromise(client) { + return new Promise((resolve, reject) => { + client.frameParent(result => { + if (result.error) { + reject(result.error); + } else { + resolve(); + } + }); + }); +} + +function promiseSome(list, iterator) { + var p = Promise.resolve(false); + list.forEach((item, index) => { + p = p.then(result => { + if (result) { + return true; + } else { + return iterator(item); + } + }) + }); + return p; +} + +function findSelectorInsideFrame(client, selector) { + return elementPresentPromise(client, selector).then(found => { + return !!found || + elementListPromise(client, 'iframe') + .then(frames => promiseSome(frames, frame => + framePromise(client, frame) + .then(() => { + return findSelectorInsideFrame(client, selector); + }) + .then(result => { + if (result) { + return true; + } else { + return frameParentPromise(client).then(Promise.resolve(false)); + } + }) + .catch(err => { + // if (err) { + // console.error('Enter frame failed:', err); + // } + return false; + }) + )) + }); +} + +SelectFrameWithXpath.prototype.command = function(selector, noReset) { + var reset = noReset ? Promise.resolve() : framePromise(this.client.api, null); + reset + .then(() => findSelectorInsideFrame(this.client.api, selector)) + .then(found => { + if (!found) { + this.client.assertion(false, 'not found', 'found', 'Did not find selector <' + selector + '> in any frame.', this.abortOnFailure, this._stackTrace); + // } else { + // this.client.assertion(true, null, null, 'Found element <' + selector + '> and entered frame containing it' + + // (noReset + // ? ' without resetting to top frame' + // : ''), this.abortOnFailure); + } + this.emit('complete'); + }) + .catch(err => { + this.client.assertion(false, err, null, 'Attempt to find <' + selector + '> failed horribly'); + this.emit('complete'); + }); +} + +module.exports = SelectFrameWithXpath; diff --git a/Website/test/e2e/commands/selectPerspective.js b/Website/test/e2e/commands/selectPerspective.js new file mode 100644 index 0000000000..c0f973828d --- /dev/null +++ b/Website/test/e2e/commands/selectPerspective.js @@ -0,0 +1,15 @@ +var events = require('events'); + +function SelectPerspective() { + events.EventEmitter.call(this); +} + +SelectPerspective.prototype.command = function (perspective) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enter(perspective); + return this.client.api; +}; + +module.exports = SelectPerspective; diff --git a/Website/test/e2e/commands/selectTreeNodeAction.js b/Website/test/e2e/commands/selectTreeNodeAction.js new file mode 100644 index 0000000000..b4ea6a9552 --- /dev/null +++ b/Website/test/e2e/commands/selectTreeNodeAction.js @@ -0,0 +1,20 @@ +var events = require('events'); + +function SlectTreeNodeAction() { + events.EventEmitter.call(this); +} + +SlectTreeNodeAction.prototype.command = function (node,action) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective() + ._rightClickonTreeNode(node); + + this.client.api.selectFrame('menuitem[label="' + action + '"]'); + content + .click('menuitem[label="'+action+'"]'); + return this.client.api; +}; + +module.exports = SlectTreeNodeAction; diff --git a/Website/test/e2e/commands/setFieldValue.js b/Website/test/e2e/commands/setFieldValue.js new file mode 100644 index 0000000000..b351081f4a --- /dev/null +++ b/Website/test/e2e/commands/setFieldValue.js @@ -0,0 +1,22 @@ +var events = require('events'); + +function SetValueByLabel() { + events.EventEmitter.call(this); +} + +SetValueByLabel.prototype.command = function (fieldLabel,vlaue,inputType) { + if(inputType == null){ + inputType = "input"; + } + + this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); + + this.client.api + .useXpath() + .click('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .clearValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', vlaue).useCss(); + return this.client.api; +}; + +module.exports = SetValueByLabel; \ No newline at end of file diff --git a/Website/test/e2e/commands/setFieldValueInFieldGroup.js b/Website/test/e2e/commands/setFieldValueInFieldGroup.js new file mode 100644 index 0000000000..4312cc9053 --- /dev/null +++ b/Website/test/e2e/commands/setFieldValueInFieldGroup.js @@ -0,0 +1,24 @@ +var events = require('events'); + +function SetValueByLabelFieldGroup() { + events.EventEmitter.call(this); +} + +SetValueByLabelFieldGroup.prototype.command = function (dialogLabel,fieldLabel,vlaue,inputType) { + if(inputType == null){ + inputType = "input"; + } + if (dialogLabel == null) { + this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); + } else { + this.client.api.selectFrameWithXpath('//*[local-name() = "fieldgroup"][@label="' + dialogLabel + '"]'); + } + this.client.api + .useXpath() + .click('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .clearValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', vlaue).useCss(); + return this.client.api; +}; + +module.exports = SetValueByLabelFieldGroup; \ No newline at end of file diff --git a/Website/test/e2e/commands/switchContentTab.js b/Website/test/e2e/commands/switchContentTab.js new file mode 100644 index 0000000000..ade020688b --- /dev/null +++ b/Website/test/e2e/commands/switchContentTab.js @@ -0,0 +1,15 @@ +var util = require('util'); +var events = require('events'); + +function ContentTab() { + events.EventEmitter.call(this); +} + +ContentTab.prototype.command = function (tabName) { + this.client.api + .selectFrame('labelbox[label="'+tabName+'"]') + .click('labelbox[label="'+tabName+'"]'); + return this.client.api; +}; + +module.exports = ContentTab; diff --git a/Website/test/e2e/pageObjects/appWindow.js b/Website/test/e2e/pageObjects/appWindow.js index fb1579acb8..4cdc822931 100644 --- a/Website/test/e2e/pageObjects/appWindow.js +++ b/Website/test/e2e/pageObjects/appWindow.js @@ -19,6 +19,7 @@ module.exports = { enter: function () { this .topFrame() + .waitForElementPresent('@appFrame', 1000) .enterFrame('@appFrame'); return this; } diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index 33e85e721e..5812f42d8f 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -17,18 +17,30 @@ module.exports = { ], commands: [ { - enter: function () { + enter: function (perspective) { + if(perspective==null){ + perspective = "Content"; // for backward compatibility + } this.api.page.appWindow() .enter() - .click('#explorer explorertoolbarbutton[data-qa="Content"]') - .waitForFrameLoad('#stagedecks stagedeck[data-qa="perspectiveContent"] iframe', 1000) - .enterFrame('#stagedecks stagedeck[data-qa="perspectiveContent"] iframe'); + .waitForElementNotPresent('dialogcover[display="block"]', 1000) + .assert.elementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]') + .api.pause(200) + .click('#explorer explorertoolbarbutton[label="'+perspective+'"]') + .waitForFrameLoad('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe', 10000) + .enterFrame('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe'); return this; }, - prepare: function () { + enterActivePerspective: function () { + this.api.page.appWindow() + .enter() + .enterFrame('#stagedecks stagedeck[selected="true"] iframe'); + return this; + }, + prepare: function (perspective) { this.api.page.appWindow().prepare(); this - .enter() + .enter(perspective) .waitForElementVisible('@browserFrame', 2000) .waitForFrameLoad('@browserFrame', 1000); return this; @@ -41,7 +53,7 @@ module.exports = { .enterFrame('view:nth-of-type(' + index + ') window iframe') return this; }, - assertBrowserContains: function (selector, value) { + _assertBrowserContains: function (selector, value) { this .enter() .enterFrame('@browserFrame') @@ -51,6 +63,16 @@ module.exports = { .assert.containsText(selector, value); return this; }, + _assertBrowserContainsAttribute: function (selector,attribiute, value) { + this + .enter() + .enterFrame('@browserFrame') + .waitForElementVisible('#browsertabbox iframe', 1000) + .waitForFrameLoad('#browsertabbox iframe', 1000) + .enterFrame('#browsertabbox iframe') + .assert.attributeContains(selector,attribiute, value) + return this; + }, assertBrowserUrl: function (url) { var urlRegex = new RegExp(url.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&') + '$'); this diff --git a/Website/test/e2e/pageObjects/editor.js b/Website/test/e2e/pageObjects/editor.js index 336e60d060..bc5130201d 100644 --- a/Website/test/e2e/pageObjects/editor.js +++ b/Website/test/e2e/pageObjects/editor.js @@ -12,36 +12,59 @@ module.exports = { commands: [ { enter: function () { - this - .waitForElementVisible('@editorFrame', 3000) - .waitForFrameLoad('@editorFrame', 3000) - .enterFrame('@editorFrame') - .waitForFrameLoad('iframe[src^="tinymce.aspx"]', 10000) // Potentially v. slow - .enterFrame('iframe[src^="tinymce.aspx"]') - .waitForFrameLoad('#editor_ifr', 3000) - .enterFrame('#editor_ifr') + this.client.api + .useXpath() + .selectFrameWithXpath('//*[@data-id="editor"]').useCss() + return this; }, changeElementContent: function (selector, newContent) { - // Enter frame with editor content this .enter() - // Check that it is editable .assert.attributeEquals('body', 'contenteditable', 'true') - // Check that it has content .section.editorBody .assert.visible(selector) - // Change header .replaceContent(selector, newContent) return this; }, - save: function () { - this.selectFrame('#savebutton'); - this.expect.element('#savebutton').to.not.have.attribute('isdisabled'); - this.click('#savebutton > labelbox'); - this.api.pause(1000) - this.expect.element('#savebutton').to.have.attribute('isdisabled'); - return this; + selcetActionOnContent: function (number, action) { + this + .enter() + .assert.attributeEquals('body', 'contenteditable', 'true') + .client.api.useXpath() + .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',3000) + .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) + .mouseButtonClick('right') + .selectFrameWithXpath('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"]') + .waitForElementVisible('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]',3000) + .click('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]').useCss() + return this; + }, + selectEditOnContent: function (number) { + this + .enter() + .assert.attributeEquals('body', 'contenteditable', 'true') + .client.api.useXpath() + .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',3000) + .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) + .doubleClick() + return this; + }, + acceptChanges: function (){ + this + .enter() + .client.api.useXpath() + .selectFrameWithXpath('//*[@response="accept"]') + .click('//*[@response="accept"]').useCss(); + return this; + }, + acceptFunctionEdit: function (){ + this + .enter() + .client.api.useXpath() + .selectFrameWithXpath('//*[@callbackid="buttonAccept"]') + .click('//*[@callbackid="buttonAccept"]').useCss(); + return this; } } ], diff --git a/Website/test/e2e/pageObjects/systemView.js b/Website/test/e2e/pageObjects/systemView.js index fffae22e0f..636ae76440 100644 --- a/Website/test/e2e/pageObjects/systemView.js +++ b/Website/test/e2e/pageObjects/systemView.js @@ -3,29 +3,56 @@ module.exports = { { systemFrame: 'iframe[src="/Composite/content/views/systemview/systemview.aspx"]'} ], commands: [{ - enter: function () { + enter: function (perspective) { this.api.page.content() - .enter() + .enter(perspective) .enterFrame('@browserFrame'); this .waitForFrameLoad('@systemFrame', 1000) .enterFrame('@systemFrame'); return this; }, - openTreeNode: function (label) { - var selector = 'treenode[label="' + label + '"] > labelbox'; + enterActivePerspective: function () { + this.api.page.content() + .enterActivePerspective() + .enterFrame('@browserFrame'); + this + .waitForFrameLoad('@systemFrame', 1000) + .enterFrame('@systemFrame'); + return this; + }, + _openTreeNode: function (parentLabel,childLabel) { + var selector = 'treenode[label="' + parentLabel + '"] > '; + if (childLabel) { + selector += 'treenode[label="' + childLabel + '"] > '; + } + selector += 'labelbox'; + this.api.waitForElementPresent(selector,1000) this.doubleClickSelector(selector); this.api.pause(300); return this; }, - selectTreeNode: function (label) { - var selector = 'treenode[label="' + label + '"] > labelbox'; + _selectTreeNode: function (parentLabel,childLabel) { + var selector = 'treenode[label="' + parentLabel + '"] > '; + if (childLabel) { + selector += 'treenode[label="' + childLabel + '"] > '; + } + selector +='labelbox'; + this.api.waitForElementPresent(selector,1000) this.click(selector); return this; }, - // Checks that a node in the system tree has children. If a child label - // is passed, checks for that specific child. - assertTreeNodeHasChild: function (parentLabel, childLabel) { + _rightClickonTreeNode: function (parentLabel,childLabel) { + var selector = 'treenode[label="' + parentLabel + '"] > '; + if (childLabel) { + selector += 'treenode[label="' + childLabel + '"] > '; + } + selector +='labelbox'; + this.api.waitForElementPresent(selector,1000) + this.rightClickSelector(selector); + return this; + }, + _assertTreeNodeHasChild: function (parentLabel, childLabel) { var selector = 'treenode[label="' + parentLabel + '"] > treenode'; if (childLabel) { selector += '[label="' + childLabel + '"]'; @@ -34,14 +61,27 @@ module.exports = { .element(selector) .to.be.present; }, - assertTreeNodeHasNoChild: function (parentLabel, childLabel) { + _assertTreeNodeIsEmpty: function (parentLabel,childLabel) { var selector = 'treenode[label="' + parentLabel + '"] > treenode'; if (childLabel) { - selector += '[label="' + childLabel + '"]'; + selector += '[label="' + childLabel + '"] > treenode'; } this.expect .element(selector) - .to.not.be.present; + .not.to.be.present; + + + }, + _assertTreeNodeIsNotEmpty: function (parentLabel,childLabel) { + var selector = 'treenode[label="' + parentLabel + '"] > treenode'; + if (childLabel) { + selector += '[label="' + childLabel + '"] > treenode'; + } + this.expect + .element(selector) + .to.be.present; + + } }] }; From 3521588bfecbf80daa1d8a4817fb2fbbb89af986 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 14 Sep 2016 12:29:31 +0200 Subject: [PATCH 27/95] rewriting test scripts with new api + correction --- .../test/e2e/suite/000_setup/installSite.js | 2 +- Website/test/e2e/suite/100_login/devMode.js | 2 +- .../test/e2e/suite/300_appWindow/stages.js | 6 +- .../test/e2e/suite/400_content/browseTree.js | 2 - .../test/e2e/suite/400_content/multiEditor.js | 90 ++++++------------- .../e2e/suite/400_content/singleEditor.js | 56 ++++-------- 6 files changed, 46 insertions(+), 112 deletions(-) diff --git a/Website/test/e2e/suite/000_setup/installSite.js b/Website/test/e2e/suite/000_setup/installSite.js index 7074c173ba..589fe34033 100644 --- a/Website/test/e2e/suite/000_setup/installSite.js +++ b/Website/test/e2e/suite/000_setup/installSite.js @@ -17,7 +17,7 @@ module.exports = { beforeEach: function (browser) { // 1 Launch an uninitialized website. browser - .url(browser.launchUrl + '/Composite/top.aspx?mode=develop') + .url(browser.launchUrl + '/Composite/top.aspx') .waitForElementVisible('.welcomepage', 10000); }, 'install Venus starter site': function (browser) { diff --git a/Website/test/e2e/suite/100_login/devMode.js b/Website/test/e2e/suite/100_login/devMode.js index 005868fce6..900c9114c2 100644 --- a/Website/test/e2e/suite/100_login/devMode.js +++ b/Website/test/e2e/suite/100_login/devMode.js @@ -1,6 +1,6 @@ module.exports = { 'Development mode has prefilled credentials': function (browser) { - browser.url(browser.launchUrl + '/Composite/top.aspx?mode=develop'); + browser.url(browser.launchUrl + '/Composite/top.aspx'); login = browser.page.login(); login.assert.value('@usernameInput', 'admin'); login.assert.value('@passwordInput', '123456'); diff --git a/Website/test/e2e/suite/300_appWindow/stages.js b/Website/test/e2e/suite/300_appWindow/stages.js index 08adbc75f0..32de40a7ee 100644 --- a/Website/test/e2e/suite/300_appWindow/stages.js +++ b/Website/test/e2e/suite/300_appWindow/stages.js @@ -1,8 +1,8 @@ const PERSPECTIVES = [ 'Content', 'Media', - 'Datas', - 'Design', + 'Data', + 'Layout', 'Functions', 'System' ] @@ -14,7 +14,7 @@ module.exports = { app.prepare().enter(); PERSPECTIVES.forEach((perspective, index) => { - var buttonSelector = 'explorertoolbarbutton[data-qa="' + perspective + '"]'; + var buttonSelector = 'explorertoolbarbutton[label="' + perspective + '"]'; var stageSelector = 'stagedeck[data-qa="perspective' + perspective + '"]'; browser .pause(1000) diff --git a/Website/test/e2e/suite/400_content/browseTree.js b/Website/test/e2e/suite/400_content/browseTree.js index fd609f6810..fac12604c3 100644 --- a/Website/test/e2e/suite/400_content/browseTree.js +++ b/Website/test/e2e/suite/400_content/browseTree.js @@ -29,8 +29,6 @@ module.exports = { systemView.assertTreeNodeHasChild('Getting Started', 'Tests'); // 7 Select the “Tests” page The “Test” page gets selected in the tree. systemView.openTreeNode('Tests') - systemView.assertTreeNodeHasNoChild('Tests', 'Foo') - systemView.assertTreeNodeHasNoChild('Features') // The “Test” page’s content loads in the browser view. content .assertBrowserContains('div.content-column > h1', 'Test the design') diff --git a/Website/test/e2e/suite/400_content/multiEditor.js b/Website/test/e2e/suite/400_content/multiEditor.js index 22f7d0d498..73cc8ea54a 100644 --- a/Website/test/e2e/suite/400_content/multiEditor.js +++ b/Website/test/e2e/suite/400_content/multiEditor.js @@ -1,75 +1,37 @@ module.exports = { + '@tags': ['Content'], beforeEach: function (browser) { browser.url(browser.launchUrl + '/Composite/top.aspx'); var content = browser.page.content(); content - .prepare(); + .prepare(); }, 'can edit front page': function (browser) { - var content = browser.page.content(); - var editor = browser.page.editor(); - var systemView = browser.page.systemView(); - // Default situation: One open docktab showing content browser, with tab view. - // Select the one open tab - content - .section.docktabs.clickTab(1); - // Find the home page in the system tree. - systemView - .enter() - .selectTreeNode('Venus Starter Site') - .leaveFrame() - content - // Click edit button - .click('toolbarbutton[label="Edit Page"]') - // Locate and check editor screen - // Relies on it being inside the second docktab frame in existence. - .enterTabFrame(2) - // Enter frame with editor content - editor - .enter() - // Check that it has more than just one entry - .section.editorBody - .waitForElementVisible('img:nth-child(2)', 1000) - // Select the first element - .click('img:nth-child(1)') - browser - // Click the toolbar button for properties - .clickInFrame('toolbarbutton[cmd="compositeInsertRendering"]', 1000) - // Click the edit HTML button - .clickInFrame('#renderingdialogpage', 'htmldatadialog', 1000) - // Find the editor in the dialog that just appeared - editor - .selectFrame('#masterdialogset') - .enterFrame('@wysiwygFrame') - .selectFrame('@editorFrame', true) - // Change the content - .changeElementContent('h1 > em', 'Jupiter'); - // Approve the change - browser - .selectFrame('#masterdialogset') - .selectFrame('#visualeditor', true) - .click('clickbutton[response="accept"]'); - // Close the properties dialog browser - .clickInFrame('#renderingdialogpage', 'clickbutton[callbackid="buttonAccept"]', 1000); - // Save change. - editor.save() - // Close editor after you - content - .enter() // Reset to content frame - .section.docktabs.closeTab(2); - // Check that the change is made - content - .assertBrowserContains('div.jumbotron-content > h1 > em', 'Jupiter'); + .selectPerspective("Content") + .selectTreeNodeAction("Venus Starter Site", "Edit Page") + .page.editor() + .selectEditOnContent(1) + .clickDataBySibilings("Statement content") + .changeElementContent('h1 > em', 'Jupiter') + .acceptChanges() + .clickDataBySibilings("Background Image") + .clickLabel("Select…") + .clickLabel("Copenhagen","Media Archive") + .clickLabel("Botanical_Garden__Photographer_Ty_Stange.jpg") + .acceptChanges() + .acceptFunctionEdit() + .clickSave() + .closeDocumentTab("Venus Starter Site") + .assertBrowserContains('div.jumbotron-content > h1 > em', 'Jupiter') + .assertBrowserContainsAttribute('div.jumbotron', 'style', 'Botanical_Garden__Photographer_Ty_Stange.jpg') + }, afterEach: function (browser, done) { - var content = browser.page.content(); - // Revert changes - content - .enter() - .enterFrame('@browserFrame') - // .click('#moreactionsbutton') - .click('toolbarbutton[image="item-undo-unpublished-changes"]') - .click('toolbarbutton[image="item-publish"]', done); + browser + .selectPerspective("Content") + .selectTreeNodeAction("Venus Starter Site","Undo Changes") + .selectTreeNodeAction("Venus Starter Site","Publish") + done(); } -}; +} diff --git a/Website/test/e2e/suite/400_content/singleEditor.js b/Website/test/e2e/suite/400_content/singleEditor.js index a06507f868..8162f13f3b 100644 --- a/Website/test/e2e/suite/400_content/singleEditor.js +++ b/Website/test/e2e/suite/400_content/singleEditor.js @@ -1,53 +1,27 @@ module.exports = { + '@tags': ['Content'], beforeEach: function (browser) { browser.url(browser.launchUrl + '/Composite/top.aspx'); var content = browser.page.content(); content - .prepare(); + .prepare(); }, 'can edit simple page': function (browser) { - var content = browser.page.content(); - var editor = browser.page.editor(); - var systemView = browser.page.systemView(); - // Default situation: One open docktab showing content browser, with tab view. - // Select the one open tab - content - .section.docktabs.clickTab(1); - // Find the 'getting started' page in the system tree. - systemView - .enter() - .openTreeNode('Venus Starter Site') - .selectTreeNode('Getting Started') - .leaveFrame() - content - // Click edit button - .click('toolbarbutton[label="Edit Page"]') - // Locate and check editor screen - // Relies on it being inside the second docktab frame in existence. - .enterTabFrame(2) - // Change header in editor - editor + browser + .selectPerspective("Content") + .openTreeNode("Venus Starter Site") + .selectTreeNodeAction("Getting Started", "Edit Page") + .page.editor() .changeElementContent('h1', 'Moving forward') - browser.pause(100); - // Save change. - editor - .save() - content - // Close editor after you - .enter() // Reset to content frame - .section.docktabs.closeTab(2); - // Check that the change is made - content - .assertBrowserContains('div.content-column > h1', 'Moving forward'); + .clickSave() + .closeDocumentTab("Getting Started") + .assertBrowserContains('div.content-column > h1', 'Moving forward') }, afterEach: function (browser, done) { - var content = browser.page.content(); - // Revert changes - content - .enter() - .enterFrame('@browserFrame') - // .click('#moreactionsbutton') - .click('toolbarbutton[image="item-undo-unpublished-changes"]') - .click('toolbarbutton[image="item-publish"]', done); + browser + .selectPerspective("Content") + .selectTreeNodeAction("Getting Started","Undo Changes") + .selectTreeNodeAction("Getting Started","Publish") + done(); } } From 5cb547031afbcbffca5f4c4260dea17b28521e77 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 14 Sep 2016 12:30:47 +0200 Subject: [PATCH 28/95] defining new language for notepad++ for autocomplete script functions --- .../test/e2e/ApiLang/Notepad++/Nightwatch.UDL | 64 ++++++ .../test/e2e/ApiLang/Notepad++/nightwatch.xml | 211 ++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL create mode 100644 Website/test/e2e/ApiLang/Notepad++/nightwatch.xml diff --git a/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL b/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL new file mode 100644 index 0000000000..79efb7682d --- /dev/null +++ b/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL @@ -0,0 +1,64 @@ + + + + + + + + 03/* 03/** 04*/ 04*/ 00// 01 02 + + + + + + + + ( ) [ ] { } ... . , ; + + + + + + + + + + + assertBrowserContainsAttribute assertBrowserContains assertFieldValue assertTreeNodeHasChild assertTreeNodeIsEmpty assertTreeNodeIsNotEmpty clickDataBySibilings clickDialogButton clickInFrame clickLabel clickSave replaceTextInCodeMirror selectEditOnContent clickText closeDocumentTab changeElementContent doubleClickSelector enterFrame leaveFrame openTreeNode replaceContent rightClickSelector selectActionFromToolbar selectContentTab selectDialog selectDocumentTab selectFrame selectFrameWithXpath selectPerspective selectTreeNodeAction setFieldValueInFieldGroup setFieldValue switchContentTab topFrame waitForFrameLoad acceptChanges acceptFunctionEdit + browser editor2 editor + beforeEach afterEach done + + + + + + 00" 01 02" 03' 04 05' 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml b/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml new file mode 100644 index 0000000000..9d8f1e2797 --- /dev/null +++ b/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From bcad99b700c2d93a0488e8620ae7d27b15f61c26 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 14 Sep 2016 13:37:26 +0200 Subject: [PATCH 29/95] Duplication e2e tests --- Website/test/e2e/suite/100_login/devMode.js | 8 +++ .../test/e2e/suite/500_duplicate/Duplicate.js | 26 +++++++ .../500_duplicate/DuplicatePagesWithAction.js | 35 ++++++++++ .../500_duplicate/DuplicatePagesWithData.js | 32 +++++++++ .../DuplicatePagesWithMetaData.js | 51 ++++++++++++++ .../DuplicatePagesWithMetaDataOnType.js | 69 +++++++++++++++++++ .../500_duplicate/DuplicateTreeAction.js | 41 +++++++++++ 7 files changed, 262 insertions(+) create mode 100644 Website/test/e2e/suite/100_login/devMode.js create mode 100644 Website/test/e2e/suite/500_duplicate/Duplicate.js create mode 100644 Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js create mode 100644 Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js create mode 100644 Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js create mode 100644 Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js create mode 100644 Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js diff --git a/Website/test/e2e/suite/100_login/devMode.js b/Website/test/e2e/suite/100_login/devMode.js new file mode 100644 index 0000000000..900c9114c2 --- /dev/null +++ b/Website/test/e2e/suite/100_login/devMode.js @@ -0,0 +1,8 @@ +module.exports = { + 'Development mode has prefilled credentials': function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + login = browser.page.login(); + login.assert.value('@usernameInput', 'admin'); + login.assert.value('@passwordInput', '123456'); + } +}; diff --git a/Website/test/e2e/suite/500_duplicate/Duplicate.js b/Website/test/e2e/suite/500_duplicate/Duplicate.js new file mode 100644 index 0000000000..38ecf4f846 --- /dev/null +++ b/Website/test/e2e/suite/500_duplicate/Duplicate.js @@ -0,0 +1,26 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare(); + }, + 'can duplicate simple page': function (browser) { + + browser + .selectPerspective("Content") + .openTreeNode("Venus Starter Site") + .selectTreeNodeAction("Getting Started", "Duplicate Page") + .assertTreeNodeHasChild('Websites', 'Venus Starter Site') + .assertTreeNodeHasChild('Venus Starter Site', 'Copy of Getting Started'); + + }, + afterEach: function (browser, done) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Copy of Getting Started","Delete") + .clickDialogButton("OK") + done(); + } +} diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js new file mode 100644 index 0000000000..bf167c0b41 --- /dev/null +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js @@ -0,0 +1,35 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare(); + }, + 'asserts duplicated simple page contains application attached to original page but not the data': function (browser) { + browser + .selectPerspective("Content") + .openTreeNode("Venus Starter Site") + .selectTreeNodeAction("Blog", "Duplicate Page") + .assertTreeNodeHasChild('Websites', 'Venus Starter Site') + .assertTreeNodeHasChild('Venus Starter Site') + .assertTreeNodeHasChild('Venus Starter Site', 'Copy of Blog') + .openTreeNode("Blog") + .assertTreeNodeHasChild('Blog') + .assertTreeNodeHasChild('Blog', 'Blog Entries') + .openTreeNode('Blog','Blog Entries') + .assertTreeNodeIsNotEmpty('Blog','Blog Entries') + .openTreeNode('Copy of Blog') + .assertTreeNodeHasChild('Copy of Blog') + .assertTreeNodeHasChild('Copy of Blog', 'Blog Entries') + .openTreeNode('Copy of Blog','Blog Entries') + .assertTreeNodeIsEmpty('Copy of Blog','Blog Entries') + }, + afterEach: function (browser, done) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Copy of Blog","Delete") + .clickDialogButton("OK") + done(); + } +} diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js new file mode 100644 index 0000000000..a1e26fc0fe --- /dev/null +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js @@ -0,0 +1,32 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare(); + }, + 'asserts duplicated simple page contains Data Folder attached to original page but not the data': function (browser) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Venus Starter Site", "Duplicate Page") + .assertTreeNodeHasChild('Websites', 'Venus Starter Site') + .assertTreeNodeHasChild('Websites', 'Copy of Venus Starter Site') + .openTreeNode('Venus Starter Site') + .assertTreeNodeHasChild('Venus Starter Site', 'Top links') + .openTreeNode('Venus Starter Site','Top links') + .assertTreeNodeIsNotEmpty('Venus Starter Site','Top links') + .openTreeNode('Copy of Venus Starter Site') + .assertTreeNodeHasChild('Copy of Venus Starter Site', 'Top links') + .openTreeNode('Copy of Venus Starter Site', 'Top links') + .assertTreeNodeIsEmpty('Copy of Venus Starter Site', 'Top links') + + }, + afterEach: function (browser, done) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Copy of Venus Starter Site","Delete") + .clickDialogButton("OK") + done(); + } +} diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js new file mode 100644 index 0000000000..2f197574d6 --- /dev/null +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js @@ -0,0 +1,51 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare("Content"); + }, + 'can duplicate simple page with Metadata attached': function (browser) { + browser + .selectPerspective("Data") + .selectTreeNodeAction("Page Metatypes", "Add Metatype") + .selectDocumentTab("New Page Metatype") + .setFieldValue("Title", "Human title") + .setFieldValue("Type namespace", "newNamespace") + .setFieldValue("Type name", "myTypeName") + .selectContentTab("Fields") + .clickLabel("Add New") + .clickSave() + .closeDocumentTab("New Page Metatype") + + .selectPerspective("Content") + .openTreeNode("Venus Starter Site") + .selectTreeNodeAction("Getting Started","Add Metadata Field") + .selectDialog("Add Metadata Field") + .clickDialogButton("Next") + .clickDialogButton("Next") + .setFieldValue("NewField", "newTextValue") + .clickDialogButton("Finish") + + .selectTreeNodeAction("Getting Started","Duplicate Page") + .selectTreeNodeAction("Copy of Getting Started","Edit Page") + .selectContentTab("Metadata") + .assertFieldValue("Human title","NewField","newTextValue") + .closeDocumentTab("Copy of Getting Started") + + }, + afterEach: function (browser, done) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Getting Started","Remove Metadata Field") + .clickDialogButton("OK") + .selectTreeNodeAction("Copy of Getting Started","Delete") + .clickDialogButton("OK") + .selectPerspective("Data") + .selectTreeNodeAction("newNamespace.myTypeName","Delete") + .clickDialogButton("OK") + done(); + } +} + diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js new file mode 100644 index 0000000000..6206af222b --- /dev/null +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js @@ -0,0 +1,69 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare("Content"); + }, + 'can duplicate simple page with Metadata attached to page type': function (browser) { + browser + .selectPerspective("Data") + .selectTreeNodeAction("Page Metatypes", "Add Metatype") + .selectDocumentTab("New Page Metatype") + .setFieldValue("Title", "Human title") + .setFieldValue("Type namespace", "newNamespace") + .setFieldValue("Type name", "myTypeName") + .selectContentTab("Fields") + .clickLabel("Add New") + .clickSave() + .closeDocumentTab("New Page Metatype") + .assertTreeNodeHasChild("Page Metatypes","newNamespace.myTypeName") + + .selectPerspective("Layout") + .openTreeNode("Page") + .selectTreeNodeAction("Metadata Fields","Add Metadata Field") + .clickDataBySibilings("Metadata type") + .clickLabel("Human title") + .setFieldValue("Programmatic name","newName") + .setFieldValue("Show with label","newLabel") + .clickDialogButton("Next") + .setFieldValue("NewField", "newTextValue") + .clickDialogButton("Finish") + + .selectPerspective("Content") + .openTreeNode("Venus Starter Site") + .selectTreeNodeAction("Getting Started","Edit Page") + .selectContentTab("Metadata") + .setFieldValueInFieldGroup("newLabel","NewField","anotherTextValue") + .clickSave() + .closeDocumentTab("Getting Started") + + .selectTreeNodeAction("Getting Started","Duplicate Page") + .selectTreeNodeAction("Copy of Getting Started","Edit Page") + .selectContentTab("Metadata") + .assertFieldValue("newLabel","NewField","anotherTextValue") + .closeDocumentTab("Copy of Getting Started") + + }, + afterEach: function (browser, done) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Getting Started","Undo Changes") + .selectTreeNodeAction("Getting Started","Publish") + .selectTreeNodeAction("Copy of Getting Started","Delete") + .clickDialogButton("OK") + + .selectPerspective("Layout") + .openTreeNode("Metadata Fields") + .selectTreeNodeAction("newName","Delete Metadata Field") + .clickDialogButton("OK") + + .selectPerspective("Data") + .selectTreeNodeAction("newNamespace.myTypeName","Delete") + .clickDialogButton("OK") + + done(); + } +} + diff --git a/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js b/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js new file mode 100644 index 0000000000..d06a3cea83 --- /dev/null +++ b/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js @@ -0,0 +1,41 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare(); + }, + 'can use duplicate action on tree': function (browser) { + browser + .selectPerspective("System") + .openTreeNode("/") + .openTreeNode("App_Data") + .openTreeNode("App_Data","Composite") + .openTreeNode("TreeDefinitions") + .selectTreeNodeAction("Composite.Community.Blog.Entries.xml","Edit File") + .replaceTextInCodeMirror('','') + .clickSave() + .closeDocumentTab("Composite.Community.Blog.Entries.xml") + .selectPerspective("Content") + .openTreeNode("Venus Starter Site") + .openTreeNode("Blog") + .openTreeNode("Blog Entries") + .openTreeNode("2014 June") + .selectTreeNodeAction("About this blog","Duplicate Blog Entry") + .assertTreeNodeHasChild("2014 June","Copy of About this blog") + + }, + afterEach: function (browser, done) { + browser + .selectPerspective("Content") + .selectTreeNodeAction("Copy of About this blog","Delete Blog Entry") + .clickDialogButton("OK") + .selectPerspective("System") + .selectTreeNodeAction("Composite.Community.Blog.Entries.xml","Edit File") + .replaceTextInCodeMirror('','') + .clickSave() + .closeDocumentTab("Composite.Community.Blog.Entries.xml") + done(); + } +} From 6dbe37e9e2a972b0a5dfbe25e32dfa986e6c881b Mon Sep 17 00:00:00 2001 From: Taras Nakonechnyi Date: Thu, 15 Sep 2016 11:44:55 +0300 Subject: [PATCH 30/95] fix 404 IPage bug --- Website/Composite/scripts/source/top/ui/bindings/Binding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website/Composite/scripts/source/top/ui/bindings/Binding.js b/Website/Composite/scripts/source/top/ui/bindings/Binding.js index 96a5598c3a..c8b1811c4b 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/Binding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/Binding.js @@ -618,7 +618,7 @@ Binding.prototype._initializeBindingTestFeatures = function () { if (Application.isTestEnvironment) { var label = this.getProperty("label"); - if (label && label.indexOf("${string:") > -1) { + if (label && label.indexOf && label.indexOf("${string:") > -1) { this.setProperty("data-qa", label); } } From bdcb764872bcce5461cf605ee8401fc796fb0980 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Thu, 15 Sep 2016 16:33:48 +0200 Subject: [PATCH 31/95] Tree definitions - fixing exceptions in the log caused by grouping elements --- .../Trees/DataFolderElementsTreeNode.cs | 32 ++++-- .../Trees/Foundation/DateTimeFormater.cs | 97 ++++++------------- 2 files changed, 55 insertions(+), 74 deletions(-) diff --git a/Composite/C1Console/Trees/DataFolderElementsTreeNode.cs b/Composite/C1Console/Trees/DataFolderElementsTreeNode.cs index 592814ab41..b8c31ba8c5 100644 --- a/Composite/C1Console/Trees/DataFolderElementsTreeNode.cs +++ b/Composite/C1Console/Trees/DataFolderElementsTreeNode.cs @@ -285,13 +285,20 @@ private IEnumerable CreateSimpleElements(EntityToken parentEntityToken, referenceValue, dynamicContext, pair.Label, - f => f.GroupingValues.Add(this.GroupingValuesFieldName, this.DateTimeFormater.Serialize(pair.Object)) + f => f.GroupingValues.Add(this.GroupingValuesFieldName, ConvertGroupingValue(pair.Object)) ); yield return element; } } + private object ConvertGroupingValue(object value) + { + return this.DateTimeFormater.IsDateTimeGroupingValue(value) + ? this.DateTimeFormater.Serialize(value) + : value; + } + private Func GetLabelFunction(out bool shouldBeSortedByLabel) { if (this.PropertyInfo.PropertyType == typeof(DateTime)) @@ -799,21 +806,32 @@ private bool CreateFilterExpression_GetFolderIndexFromDataEntityToken(DataEntity private Expression CreateSimpleFilterExpression(object value, Expression fieldExpression) { - if (this.PropertyInfo.PropertyType != typeof(DateTime) && this.PropertyInfo.PropertyType != typeof(DateTime?)) + Type propertyType = this.PropertyInfo.PropertyType; + if (propertyType == typeof (DateTime) || propertyType == typeof (DateTime?)) { - Expression expression = Expression.Equal(fieldExpression, Expression.Constant(value, this.PropertyInfo.PropertyType)); + return CreateFilterByDateTimeExpression(value, fieldExpression); + } - return expression; + if (value != null && !propertyType.IsInstanceOfType(value)) + { + Exception ex; + value = ValueTypeConverter.TryConvert(value, propertyType, out ex); + if (ex != null) + { + throw new InvalidOperationException($"Failed to convent a filtering value to type '{propertyType}'"); + } } + return Expression.Equal(fieldExpression, Expression.Constant(value, propertyType)); + } + private Expression CreateFilterByDateTimeExpression(object value, Expression fieldExpression) + { DateTime dateTime = DateTimeFormater.Deserialize(value.ToString()); if (this.DateFormat == null) { - Expression expression = Expression.Equal(fieldExpression, Expression.Constant(dateTime)); - - return expression; + return Expression.Equal(fieldExpression, Expression.Constant(dateTime)); } diff --git a/Composite/C1Console/Trees/Foundation/DateTimeFormater.cs b/Composite/C1Console/Trees/Foundation/DateTimeFormater.cs index 1a7008f61d..7912d8a2a5 100644 --- a/Composite/C1Console/Trees/Foundation/DateTimeFormater.cs +++ b/Composite/C1Console/Trees/Foundation/DateTimeFormater.cs @@ -22,32 +22,9 @@ internal sealed class DateTimeFormater private static readonly IList Tuples_Constructors; private static readonly IList Tuples_Members; - //private static readonly IList AnonymousTypes_Constructors; - //private static readonly IList AnonymousTypes_Members; - static DateTimeFormater() { - var objects = new object[] - { - new {Item1 = 0}, - new {Item1 = 0, Item2 = 0}, - new {Item1 = 0, Item2 = 0, Item3 = 0}, - new {Item1 = 0, Item2 = 0, Item3 = 0, Item4 = 0}, - new {Item1 = 0, Item2 = 0, Item3 = 0, Item4 = 0, Item5 = 0}, - new {Item1 = 0, Item2 = 0, Item3 = 0, Item4 = 0, Item5 = 0, Item6 = 0} - }; - - //AnonymousTypes_Constructors = new List(); - //AnonymousTypes_Members = new List(); - //for (int i = 0; i < objects.Length; i++) - //{ - // var type = objects[i].GetType(); - - // AnonymousTypes_Constructors.Add(type.GetConstructors()[0]); - // AnonymousTypes_Members.Add(type.GetProperties().Select(p => p.GetGetMethod()).ToArray()); - //} - - var tupleTypes = new Type[] + var tupleTypes = new[] { typeof (Tuple), typeof (Tuple), @@ -69,6 +46,20 @@ static DateTimeFormater() } + public bool IsDateTimeGroupingValue(object value) + { + if (value == null) + { + return false; + } + + var type = value.GetType(); + return type.FullName.StartsWith(typeof(Tuple).FullName) + && type.IsGenericType + && type.GetGenericArguments().All(a => a == typeof(int)); + } + + public DateTimeFormater(string format) { _format = format; @@ -118,7 +109,7 @@ public string FormatLabel(object dateTimeValue) public string Serialize(object value) { - if (this.IsFormated == false) + if (!this.IsFormated) { TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(DateTime)); return typeConverter.ConvertToString(value); @@ -299,69 +290,41 @@ private void ValidateFieldsCount() Verify.That(_fieldCount < Tuples_Constructors.Count, "To many fields specified: {0}", _fieldCount); } - public bool IsFormated - { - get { return _format != null; } - } + public bool IsFormated => _format != null; + public bool HasYear => _yearFormat != null; - public bool HasYear - { - get { return _yearFormat != null; } - } + public bool HasMonth => _monthFormat != null; - public bool HasMonth - { - get { return _monthFormat != null; } - } - + public bool HasDay => _dayFormat != null; - public bool HasDay - { - get { return _dayFormat != null; } - } + public bool HasHour => _hourFormat != null; + public bool HasMinute => _minuteFormat != null; - public bool HasHour - { - get { return _hourFormat != null; } - } - - - - public bool HasMinute - { - get { return _minuteFormat != null; } - } - - - - public bool HasSecond - { - get { return _secondFormat != null; } - } + public bool HasSecond => _secondFormat != null; private void SetFormat(string pattern, ref string format) { - if ((this._format.Contains(pattern)) && (format == null)) + if (_format.Contains(pattern) && format == null) { format = pattern; _fieldCount++; } } - public static PropertyInfo DateTime_Year = typeof(DateTime).GetProperty("Year"); - public static PropertyInfo DateTime_Month = typeof(DateTime).GetProperty("Month"); - public static PropertyInfo DateTime_Day = typeof(DateTime).GetProperty("Day"); - public static PropertyInfo DateTime_Hour = typeof(DateTime).GetProperty("Hour"); - public static PropertyInfo DateTime_Minute = typeof(DateTime).GetProperty("Minute"); - public static PropertyInfo DateTime_Second = typeof(DateTime).GetProperty("Second"); + public static PropertyInfo DateTime_Year = typeof(DateTime).GetProperty(nameof(DateTime.Year)); + public static PropertyInfo DateTime_Month = typeof(DateTime).GetProperty(nameof(DateTime.Month)); + public static PropertyInfo DateTime_Day = typeof(DateTime).GetProperty(nameof(DateTime.Day)); + public static PropertyInfo DateTime_Hour = typeof(DateTime).GetProperty(nameof(DateTime.Hour)); + public static PropertyInfo DateTime_Minute = typeof(DateTime).GetProperty(nameof(DateTime.Minute)); + public static PropertyInfo DateTime_Second = typeof(DateTime).GetProperty(nameof(DateTime.Second)); } } From db8fef917f94018c848ebf229e8dada42d28f5f6 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Fri, 16 Sep 2016 13:32:33 +0200 Subject: [PATCH 32/95] fixes for selenium hangs after failure --- .../assertBrowserContainsWithXpath.js | 16 ++++++ Website/test/e2e/commands/clickSave.js | 2 +- Website/test/e2e/commands/setFieldValue.js | 9 ++-- .../e2e/commands/setFieldValueInFieldGroup.js | 5 +- .../e2e/commands/waitForFrameLoadwithXpath.js | 49 +++++++++++++++++++ Website/test/e2e/pageObjects/content.js | 11 +++++ Website/test/e2e/pageObjects/editor.js | 3 ++ Website/test/e2e/suite/100_login/procedure.js | 4 +- .../test/e2e/suite/300_appWindow/stages.js | 2 +- .../test/e2e/suite/400_content/multiEditor.js | 4 +- .../e2e/suite/400_content/singleEditor.js | 5 +- nightwatch.json | 23 +++++++-- 12 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 Website/test/e2e/commands/assertBrowserContainsWithXpath.js create mode 100644 Website/test/e2e/commands/waitForFrameLoadwithXpath.js diff --git a/Website/test/e2e/commands/assertBrowserContainsWithXpath.js b/Website/test/e2e/commands/assertBrowserContainsWithXpath.js new file mode 100644 index 0000000000..75f712b792 --- /dev/null +++ b/Website/test/e2e/commands/assertBrowserContainsWithXpath.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertBrowserContains() { + events.EventEmitter.call(this); +} + +AssertBrowserContains.prototype.command = function (selector) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective(); + content._assertBrowserContains(selector); + return this.client.api; +}; + +module.exports = AssertBrowserContains; diff --git a/Website/test/e2e/commands/clickSave.js b/Website/test/e2e/commands/clickSave.js index c93a0380d3..01e2f3c7c1 100644 --- a/Website/test/e2e/commands/clickSave.js +++ b/Website/test/e2e/commands/clickSave.js @@ -9,7 +9,7 @@ ClickSave.prototype.command = function () { .selectFrame('#savebutton'); this.client.api.expect.element('#savebutton').to.not.have.attribute('isdisabled'); this.client.api.click('#savebutton > labelbox'); - this.client.api.waitForElementVisible('#savebutton[isdisabled="true"]',20000); + this.client.api.waitForElementVisible('#savebutton[isdisabled="true"]',60000); return this.client.api; }; diff --git a/Website/test/e2e/commands/setFieldValue.js b/Website/test/e2e/commands/setFieldValue.js index b351081f4a..dd52c89baa 100644 --- a/Website/test/e2e/commands/setFieldValue.js +++ b/Website/test/e2e/commands/setFieldValue.js @@ -4,7 +4,7 @@ function SetValueByLabel() { events.EventEmitter.call(this); } -SetValueByLabel.prototype.command = function (fieldLabel,vlaue,inputType) { +SetValueByLabel.prototype.command = function (fieldLabel,value,inputType) { if(inputType == null){ inputType = "input"; } @@ -12,11 +12,12 @@ SetValueByLabel.prototype.command = function (fieldLabel,vlaue,inputType) { this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); this.client.api - .useXpath() + .useXpath() .click('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') .clearValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') - .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', vlaue).useCss(); - return this.client.api; + .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', value) + .assertFieldValue(null,fieldLabel,value,inputType) + return this.client.api; }; module.exports = SetValueByLabel; \ No newline at end of file diff --git a/Website/test/e2e/commands/setFieldValueInFieldGroup.js b/Website/test/e2e/commands/setFieldValueInFieldGroup.js index 4312cc9053..710866b91c 100644 --- a/Website/test/e2e/commands/setFieldValueInFieldGroup.js +++ b/Website/test/e2e/commands/setFieldValueInFieldGroup.js @@ -4,7 +4,7 @@ function SetValueByLabelFieldGroup() { events.EventEmitter.call(this); } -SetValueByLabelFieldGroup.prototype.command = function (dialogLabel,fieldLabel,vlaue,inputType) { +SetValueByLabelFieldGroup.prototype.command = function (dialogLabel,fieldLabel,value,inputType) { if(inputType == null){ inputType = "input"; } @@ -17,7 +17,8 @@ SetValueByLabelFieldGroup.prototype.command = function (dialogLabel,fieldLabel,v .useXpath() .click('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') .clearValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') - .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', vlaue).useCss(); + .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', value) + .assertFieldValue(dialogLabel,fieldLabel,value,inputType) return this.client.api; }; diff --git a/Website/test/e2e/commands/waitForFrameLoadwithXpath.js b/Website/test/e2e/commands/waitForFrameLoadwithXpath.js new file mode 100644 index 0000000000..96c4f837a7 --- /dev/null +++ b/Website/test/e2e/commands/waitForFrameLoadwithXpath.js @@ -0,0 +1,49 @@ +var util = require('util'); +var events = require('events'); + +function WaitForFrameLoad() { + events.EventEmitter.call(this); + this.abortOnFailure = typeof this.client.api.globals.abortOnAssertionFailure == 'undefined' || this.client.api.globals.abortOnAssertionFailure; +} + +util.inherits(WaitForFrameLoad, events.EventEmitter); + +WaitForFrameLoad.prototype.command = function(selector, timeout) { + if (!timeout) { + throw new Error('waitForFrameLoad() must have timeout.'); + } + + const complete = () => this.emit('complete'); + var isTimedOut = false; + var interval = Math.max(Math.floor(timeout / 10), 5); + var timeElapsed = interval; + var timedRecheck, timeoutTimer; + + const client = this.client; + + timeoutTimer = setTimeout(() => { + clearTimeout(timedRecheck); + client.assertion(false, null, null, 'Frame <' + selector + '> did not load within ' + timeout + 'ms', this.abortOnFailure, this._stackTrace); + complete(); + }, timeout); + + function checkFrameLoaded() { + client.api.execute(function (selector) { + var frame = document.evaluate('count('+selector+')',document,null,XPathResult.ANY_TYPE,null); + return frame.numberValue > 0; + }, [selector], (result) => { + if (result.value === true) { + clearTimeout(timeoutTimer); + client.assertion(true, null, null, 'Frame <' + selector + '> loaded within ' + timeElapsed + 'ms', this.abortOnFailure); + complete(); + } else { + timedRecheck = setTimeout(checkFrameLoaded, interval); + timeElapsed += interval; + } + }); + }; + checkFrameLoaded(); + return client.api; +}; + +module.exports = WaitForFrameLoad; diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index 5812f42d8f..73687b150b 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -63,6 +63,17 @@ module.exports = { .assert.containsText(selector, value); return this; }, + _assertBrowserContainsWithXpath: function (selector) { + this + .enter() + .enterFrame('@browserFrame') + .waitForElementVisible('#browsertabbox iframe', 1000) + .waitForFrameLoad('#browsertabbox iframe', 1000) + .enterFrame('#browsertabbox iframe') + .useXpath() + .assert.elementPresent(selector); + return this; + }, _assertBrowserContainsAttribute: function (selector,attribiute, value) { this .enter() diff --git a/Website/test/e2e/pageObjects/editor.js b/Website/test/e2e/pageObjects/editor.js index bc5130201d..828226e7ed 100644 --- a/Website/test/e2e/pageObjects/editor.js +++ b/Website/test/e2e/pageObjects/editor.js @@ -13,6 +13,7 @@ module.exports = { { enter: function () { this.client.api + .pause(400) .useXpath() .selectFrameWithXpath('//*[@data-id="editor"]').useCss() @@ -48,6 +49,8 @@ module.exports = { .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',3000) .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) .doubleClick() + .useXpath() + .pause(400) return this; }, acceptChanges: function (){ diff --git a/Website/test/e2e/suite/100_login/procedure.js b/Website/test/e2e/suite/100_login/procedure.js index 4ef0fd9d47..474585983c 100644 --- a/Website/test/e2e/suite/100_login/procedure.js +++ b/Website/test/e2e/suite/100_login/procedure.js @@ -7,9 +7,9 @@ module.exports = { .setUsername('admin') .setPassword('123456') .click('@submitButton') - .waitForElementNotVisible('@usernameField', 1000); + .waitForElementNotVisible('@usernameField', 5000); // Check that start screen is shown browser.page.appWindow().enter(); - startScreen.waitForElementVisible('@startFrame', 2000); + startScreen.waitForElementVisible('@startFrame', 5000); } }; diff --git a/Website/test/e2e/suite/300_appWindow/stages.js b/Website/test/e2e/suite/300_appWindow/stages.js index 32de40a7ee..b190d96a1c 100644 --- a/Website/test/e2e/suite/300_appWindow/stages.js +++ b/Website/test/e2e/suite/300_appWindow/stages.js @@ -19,7 +19,7 @@ module.exports = { browser .pause(1000) .click(buttonSelector) - .waitForElementVisible(stageSelector, 2000); + .waitForElementVisible(stageSelector, 5000); }); } }; diff --git a/Website/test/e2e/suite/400_content/multiEditor.js b/Website/test/e2e/suite/400_content/multiEditor.js index 73cc8ea54a..d9b529f253 100644 --- a/Website/test/e2e/suite/400_content/multiEditor.js +++ b/Website/test/e2e/suite/400_content/multiEditor.js @@ -26,12 +26,12 @@ module.exports = { .assertBrowserContains('div.jumbotron-content > h1 > em', 'Jupiter') .assertBrowserContainsAttribute('div.jumbotron', 'style', 'Botanical_Garden__Photographer_Ty_Stange.jpg') - }, - afterEach: function (browser, done) { browser .selectPerspective("Content") .selectTreeNodeAction("Venus Starter Site","Undo Changes") .selectTreeNodeAction("Venus Starter Site","Publish") + }, + afterEach: function (browser, done) { done(); } } diff --git a/Website/test/e2e/suite/400_content/singleEditor.js b/Website/test/e2e/suite/400_content/singleEditor.js index 8162f13f3b..f56249e8a0 100644 --- a/Website/test/e2e/suite/400_content/singleEditor.js +++ b/Website/test/e2e/suite/400_content/singleEditor.js @@ -16,12 +16,13 @@ module.exports = { .clickSave() .closeDocumentTab("Getting Started") .assertBrowserContains('div.content-column > h1', 'Moving forward') - }, - afterEach: function (browser, done) { + browser .selectPerspective("Content") .selectTreeNodeAction("Getting Started","Undo Changes") .selectTreeNodeAction("Getting Started","Publish") + }, + afterEach: function (browser, done) { done(); } } diff --git a/nightwatch.json b/nightwatch.json index 9dbcffb7cb..87820c7e17 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -14,9 +14,10 @@ "log_path" : "", "host" : "127.0.0.1", "port" : 4444, - "cli_args" : { + "cli_args" : { "webdriver.chrome.driver" : "Website/node_modules/chromedriver/lib/chromedriver/chromedriver.exe", "webdriver.ie.driver" : "Website/node_modules/iedriver/lib/iedriver/IEdriverServer.exe" + } }, @@ -26,20 +27,32 @@ "selenium_port" : 4444, "selenium_host" : "localhost", "silent": true, - "end_session_on_fail": false, + "end_session_on_fail": true, "skip_testcases_on_fail": false, + "globals": { + "connectionString": "" + }, "screenshots" : { "enabled" : false, - "path" : "" + "on_failure" : true, + "on_error" : true, + "path" : "Website/test/e2e/screenshots" }, "desiredCapabilities": { "browserName": "chrome", "loggingPrefs": { "browser": "ALL" } , "javascriptEnabled": true, - "acceptSslCerts": true + "acceptSslCerts": true, + "chromeOptions" : { + "args" : ["--no-sandbox"] + } } }, - + + "noSetup": { + "exclude" : ["Website/test/e2e/suite/000_setup"] + }, + "firefox" : { "desiredCapabilities": { "browserName": "firefox", From 6c33571f493bae77258c5496d32e1a8c3f58adf0 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Fri, 16 Sep 2016 13:37:29 +0200 Subject: [PATCH 33/95] fixes for selenium hangs after failure --- Website/test/e2e/suite/100_login/devMode.js | 8 -------- Website/test/e2e/suite/500_duplicate/Duplicate.js | 4 ++-- .../e2e/suite/500_duplicate/DuplicatePagesWithAction.js | 5 +++-- .../e2e/suite/500_duplicate/DuplicatePagesWithData.js | 8 +++++--- .../e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js | 8 +++++--- .../500_duplicate/DuplicatePagesWithMetaDataOnType.js | 8 ++++---- .../test/e2e/suite/500_duplicate/DuplicateTreeAction.js | 5 +++-- 7 files changed, 22 insertions(+), 24 deletions(-) delete mode 100644 Website/test/e2e/suite/100_login/devMode.js diff --git a/Website/test/e2e/suite/100_login/devMode.js b/Website/test/e2e/suite/100_login/devMode.js deleted file mode 100644 index 900c9114c2..0000000000 --- a/Website/test/e2e/suite/100_login/devMode.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - 'Development mode has prefilled credentials': function (browser) { - browser.url(browser.launchUrl + '/Composite/top.aspx'); - login = browser.page.login(); - login.assert.value('@usernameInput', 'admin'); - login.assert.value('@passwordInput', '123456'); - } -}; diff --git a/Website/test/e2e/suite/500_duplicate/Duplicate.js b/Website/test/e2e/suite/500_duplicate/Duplicate.js index 38ecf4f846..df33e235cb 100644 --- a/Website/test/e2e/suite/500_duplicate/Duplicate.js +++ b/Website/test/e2e/suite/500_duplicate/Duplicate.js @@ -15,12 +15,12 @@ module.exports = { .assertTreeNodeHasChild('Websites', 'Venus Starter Site') .assertTreeNodeHasChild('Venus Starter Site', 'Copy of Getting Started'); - }, - afterEach: function (browser, done) { browser .selectPerspective("Content") .selectTreeNodeAction("Copy of Getting Started","Delete") .clickDialogButton("OK") + }, + afterEach: function (browser, done) { done(); } } diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js index bf167c0b41..be0d95f9bb 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js @@ -24,12 +24,13 @@ module.exports = { .assertTreeNodeHasChild('Copy of Blog', 'Blog Entries') .openTreeNode('Copy of Blog','Blog Entries') .assertTreeNodeIsEmpty('Copy of Blog','Blog Entries') - }, - afterEach: function (browser, done) { + browser .selectPerspective("Content") .selectTreeNodeAction("Copy of Blog","Delete") .clickDialogButton("OK") + }, + afterEach: function (browser, done) { done(); } } diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js index a1e26fc0fe..2b435236e7 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js @@ -20,13 +20,15 @@ module.exports = { .assertTreeNodeHasChild('Copy of Venus Starter Site', 'Top links') .openTreeNode('Copy of Venus Starter Site', 'Top links') .assertTreeNodeIsEmpty('Copy of Venus Starter Site', 'Top links') - - }, - afterEach: function (browser, done) { + browser .selectPerspective("Content") .selectTreeNodeAction("Copy of Venus Starter Site","Delete") .clickDialogButton("OK") + + + }, + afterEach: function (browser, done) { done(); } } diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js index 2f197574d6..576bfa53f3 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js @@ -33,9 +33,7 @@ module.exports = { .selectContentTab("Metadata") .assertFieldValue("Human title","NewField","newTextValue") .closeDocumentTab("Copy of Getting Started") - - }, - afterEach: function (browser, done) { + browser .selectPerspective("Content") .selectTreeNodeAction("Getting Started","Remove Metadata Field") @@ -45,6 +43,10 @@ module.exports = { .selectPerspective("Data") .selectTreeNodeAction("newNamespace.myTypeName","Delete") .clickDialogButton("OK") + + + }, + afterEach: function (browser, done) { done(); } } diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js index 6206af222b..b503b6cc10 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js @@ -44,9 +44,7 @@ module.exports = { .selectContentTab("Metadata") .assertFieldValue("newLabel","NewField","anotherTextValue") .closeDocumentTab("Copy of Getting Started") - - }, - afterEach: function (browser, done) { + browser .selectPerspective("Content") .selectTreeNodeAction("Getting Started","Undo Changes") @@ -62,7 +60,9 @@ module.exports = { .selectPerspective("Data") .selectTreeNodeAction("newNamespace.myTypeName","Delete") .clickDialogButton("OK") - + + }, + afterEach: function (browser, done) { done(); } } diff --git a/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js b/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js index d06a3cea83..dcede706af 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js @@ -25,8 +25,6 @@ module.exports = { .selectTreeNodeAction("About this blog","Duplicate Blog Entry") .assertTreeNodeHasChild("2014 June","Copy of About this blog") - }, - afterEach: function (browser, done) { browser .selectPerspective("Content") .selectTreeNodeAction("Copy of About this blog","Delete Blog Entry") @@ -36,6 +34,9 @@ module.exports = { .replaceTextInCodeMirror('','') .clickSave() .closeDocumentTab("Composite.Community.Blog.Entries.xml") + + }, + afterEach: function (browser, done) { done(); } } From 62e5eaac4fa964bc55618fd1e852612bf8972bb1 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 19 Sep 2016 11:56:41 +0200 Subject: [PATCH 34/95] add sql environment / editor bug fix --- .../test/e2e/commands/clickDataBySibilings.js | 2 +- Website/test/e2e/pageObjects/editor.js | 12 +++---- .../e2e/suite/000_setup/InstalSQLPackage.js | 31 +++++++++++++++++++ Website/test/e2e/suite/100_login/devMode.js | 8 ----- nightwatch.json | 7 +++-- 5 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 Website/test/e2e/suite/000_setup/InstalSQLPackage.js delete mode 100644 Website/test/e2e/suite/100_login/devMode.js diff --git a/Website/test/e2e/commands/clickDataBySibilings.js b/Website/test/e2e/commands/clickDataBySibilings.js index 91ffbfda3c..7282a123b6 100644 --- a/Website/test/e2e/commands/clickDataBySibilings.js +++ b/Website/test/e2e/commands/clickDataBySibilings.js @@ -5,7 +5,7 @@ function ClickDataBySibiling() { } ClickDataBySibiling.prototype.command = function (vlaue) { - this.client.api.selectFrameWithXpath('//*[local-name()="fielddesc"][text()="'+vlaue+'"]/..//*[local-name()="fielddata"]'); + this.client.api.selectFrameWithXpath('//*[local-name()="fielddesc"][text()="'+vlaue+'"]'); this.client.api .useXpath() diff --git a/Website/test/e2e/pageObjects/editor.js b/Website/test/e2e/pageObjects/editor.js index 828226e7ed..040373ccb6 100644 --- a/Website/test/e2e/pageObjects/editor.js +++ b/Website/test/e2e/pageObjects/editor.js @@ -33,24 +33,24 @@ module.exports = { .enter() .assert.attributeEquals('body', 'contenteditable', 'true') .client.api.useXpath() - .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',3000) + .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',60000) .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) .mouseButtonClick('right') .selectFrameWithXpath('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"]') - .waitForElementVisible('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]',3000) + .waitForElementVisible('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]',60000) .click('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]').useCss() return this; }, selectEditOnContent: function (number) { - this + this .enter() .assert.attributeEquals('body', 'contenteditable', 'true') .client.api.useXpath() - .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',3000) + .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',60000) .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) .doubleClick() - .useXpath() - .pause(400) + this.client.api.page.appWindow().enter() + .waitForElementPresent('iframe[src="/Composite/content/dialogs/postback/postbackdialog.aspx"]',60000) return this; }, acceptChanges: function (){ diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js new file mode 100644 index 0000000000..269d7f21d6 --- /dev/null +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -0,0 +1,31 @@ +module.exports = { + '@tags': ['Duplicate'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare(); + }, + 'can duplicate simple page': function (browser) { + + browser + .selectPerspective("System") + .openTreeNode("Available Packages") + .openTreeNode("Composite.Tools") + .selectTreeNodeAction("Composite.Tools.SqlServerDataProvider", "Install") + .clickLabel("I accept the license agreement") + .clickDialogButton("Next") + .clickDialogButton("Next") + .clickDialogButton("Next") + .clickDialogButton("Finish") + + browser + .selectPerspective("System") + .openTreeNode("Installed Packages") + .openTreeNode("Composite.Tools") + .assertTreeNodeHasChild("Composite.Tools","Composite.Tools.SqlServerDataProvider") + }, + afterEach: function (browser, done) { + done(); + } +} diff --git a/Website/test/e2e/suite/100_login/devMode.js b/Website/test/e2e/suite/100_login/devMode.js deleted file mode 100644 index 900c9114c2..0000000000 --- a/Website/test/e2e/suite/100_login/devMode.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - 'Development mode has prefilled credentials': function (browser) { - browser.url(browser.launchUrl + '/Composite/top.aspx'); - login = browser.page.login(); - login.assert.value('@usernameInput', 'admin'); - login.assert.value('@passwordInput', '123456'); - } -}; diff --git a/nightwatch.json b/nightwatch.json index 87820c7e17..468d098123 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -29,11 +29,12 @@ "silent": true, "end_session_on_fail": true, "skip_testcases_on_fail": false, + "exclude" : ["Website/test/e2e/suite/000_setup/InstalSQLPackage.js"], "globals": { "connectionString": "" }, "screenshots" : { - "enabled" : false, + "enabled" : true, "on_failure" : true, "on_error" : true, "path" : "Website/test/e2e/screenshots" @@ -49,8 +50,8 @@ } }, - "noSetup": { - "exclude" : ["Website/test/e2e/suite/000_setup"] + "sql": { + "exclude" : ["Website/test/e2e/suite/000_setup/installSite.js"] }, "firefox" : { From 6c0206ab3fdf8880582981feded7a0eba4bf9152 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 19 Sep 2016 13:20:20 +0200 Subject: [PATCH 35/95] change double click to invoke function edit to select from toolbar --- Website/test/e2e/pageObjects/editor.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Website/test/e2e/pageObjects/editor.js b/Website/test/e2e/pageObjects/editor.js index 040373ccb6..6332330422 100644 --- a/Website/test/e2e/pageObjects/editor.js +++ b/Website/test/e2e/pageObjects/editor.js @@ -48,7 +48,10 @@ module.exports = { .client.api.useXpath() .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',60000) .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) - .doubleClick() + .click('//*[@id="tinymce"]/*['+number+']') + .selectFrame('toolbar[binding="VisualEditorToolBarBinding"]') + .waitForElementPresent('//*[local-name()="labeltext"][text()="Function Properties…"]',60000) + .clickText("Function Properties…") this.client.api.page.appWindow().enter() .waitForElementPresent('iframe[src="/Composite/content/dialogs/postback/postbackdialog.aspx"]',60000) return this; From daee2e64d04c612f92fa9ea7f72da0e6d2dadea7 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Mon, 19 Sep 2016 14:19:48 +0200 Subject: [PATCH 36/95] Refactoring --- Composite/C1Console/Elements/ActionHandle.cs | 20 ++------ Composite/C1Console/Elements/ElementAction.cs | 48 +++++-------------- 2 files changed, 16 insertions(+), 52 deletions(-) diff --git a/Composite/C1Console/Elements/ActionHandle.cs b/Composite/C1Console/Elements/ActionHandle.cs index 58afa52719..85688a1119 100644 --- a/Composite/C1Console/Elements/ActionHandle.cs +++ b/Composite/C1Console/Elements/ActionHandle.cs @@ -1,10 +1,4 @@ -using System; -using System.Text; -using System.Reflection; -using System.Collections.Generic; -using Composite.Core.Types; using Composite.C1Console.Security; -using Composite.Core.Serialization; namespace Composite.C1Console.Elements @@ -14,7 +8,7 @@ namespace Composite.C1Console.Elements /// public sealed class ActionHandle { - private ActionToken _actionToken; + private readonly ActionToken _actionToken; private string _serializedActionToken; @@ -33,11 +27,7 @@ public ActionHandle(ActionToken actionToken) /// /// represented by this handle. /// - public ActionToken ActionToken - { - get { return _actionToken; } - } - + public ActionToken ActionToken => _actionToken; private string SerializedActionToken @@ -56,11 +46,7 @@ private string SerializedActionToken /// - public override bool Equals(object obj) - { - return Equals(obj as ActionHandle); - } - + public override bool Equals(object obj) => Equals(obj as ActionHandle); /// diff --git a/Composite/C1Console/Elements/ElementAction.cs b/Composite/C1Console/Elements/ElementAction.cs index 33b162a5ee..ad6ab2b9b5 100644 --- a/Composite/C1Console/Elements/ElementAction.cs +++ b/Composite/C1Console/Elements/ElementAction.cs @@ -1,38 +1,39 @@ -using System; +using Composite.C1Console.Security; namespace Composite.C1Console.Elements { - /// + /// /// Define an action you can attach to an . /// public sealed class ElementAction { - private readonly ActionHandle _actionHandle; - - /// /// Constructs a new instance. /// /// public ElementAction(ActionHandle actionHandle) { - if (actionHandle == null) throw new ArgumentNullException("actionHandle"); + Verify.ArgumentNotNull(actionHandle, nameof(actionHandle)); - _actionHandle = actionHandle; + ActionHandle = actionHandle; } - /// - /// The action handle + /// Constructs a new instance. /// - public ActionHandle ActionHandle + /// + public ElementAction(ActionToken actionToken): this(new ActionHandle(actionToken)) { - get { return _actionHandle; } } + /// + /// The action handle + /// + public ActionHandle ActionHandle { get; } + /// /// The visual representation (label, icon) of the action @@ -40,34 +41,11 @@ public ActionHandle ActionHandle public ActionVisualizedData VisualData { get; set; } - /// public string TagValue { get; set; } - /// - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - - - /// - public bool Equals(ElementAction elementAction) - { - if (elementAction == null) return false; - - return this.ActionHandle.Equals(elementAction); - } - - - - /// - public override int GetHashCode() - { - return this.ActionHandle.GetHashCode(); - } + public override int GetHashCode() => this.ActionHandle.GetHashCode(); } } From ec08bdb6bf8fe4acc656025d41c3533b21384f8c Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 19 Sep 2016 14:24:54 +0200 Subject: [PATCH 37/95] Increase timeout values for system view show up --- Website/test/e2e/pageObjects/systemView.js | 10 +++++----- Website/test/e2e/suite/000_setup/InstalSQLPackage.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Website/test/e2e/pageObjects/systemView.js b/Website/test/e2e/pageObjects/systemView.js index 636ae76440..7a57a4f7e7 100644 --- a/Website/test/e2e/pageObjects/systemView.js +++ b/Website/test/e2e/pageObjects/systemView.js @@ -8,7 +8,7 @@ module.exports = { .enter(perspective) .enterFrame('@browserFrame'); this - .waitForFrameLoad('@systemFrame', 1000) + .waitForFrameLoad('@systemFrame', 10000) .enterFrame('@systemFrame'); return this; }, @@ -17,7 +17,7 @@ module.exports = { .enterActivePerspective() .enterFrame('@browserFrame'); this - .waitForFrameLoad('@systemFrame', 1000) + .waitForFrameLoad('@systemFrame', 10000) .enterFrame('@systemFrame'); return this; }, @@ -27,7 +27,7 @@ module.exports = { selector += 'treenode[label="' + childLabel + '"] > '; } selector += 'labelbox'; - this.api.waitForElementPresent(selector,1000) + this.api.waitForElementPresent(selector,10000) this.doubleClickSelector(selector); this.api.pause(300); return this; @@ -38,7 +38,7 @@ module.exports = { selector += 'treenode[label="' + childLabel + '"] > '; } selector +='labelbox'; - this.api.waitForElementPresent(selector,1000) + this.api.waitForElementPresent(selector,10000) this.click(selector); return this; }, @@ -48,7 +48,7 @@ module.exports = { selector += 'treenode[label="' + childLabel + '"] > '; } selector +='labelbox'; - this.api.waitForElementPresent(selector,1000) + this.api.waitForElementPresent(selector,10000) this.rightClickSelector(selector); return this; }, diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js index 269d7f21d6..247f60ee1d 100644 --- a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -1,12 +1,12 @@ module.exports = { - '@tags': ['Duplicate'], + '@tags': ['InstallSql'], beforeEach: function (browser) { browser.url(browser.launchUrl + '/Composite/top.aspx'); var content = browser.page.content(); content .prepare(); }, - 'can duplicate simple page': function (browser) { + 'Install SQL Package': function (browser) { browser .selectPerspective("System") From abbd8ee83b510a07561108dac6e0ccdfd102f6a1 Mon Sep 17 00:00:00 2001 From: Marcus Wendt Date: Mon, 19 Sep 2016 14:36:26 +0200 Subject: [PATCH 38/95] =?UTF-8?q?Search/replace=20to=20replace=20=E2=80=9D?= =?UTF-8?q?Composite=20C1=E2=80=9D=20and=20=E2=80=9DComposite=20A/S?= =?UTF-8?q?=E2=80=9D=20with=20=E2=80=9DOrckestra=20CMS=E2=80=9D=20and=20?= =?UTF-8?q?=E2=80=9DOrckestra=20Inc=E2=80=9D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...iewAvailablePackageInfoWorkflowWorkflow.cs | 2 +- .../Properties/AssemblyInfo.cs | 6 ++-- Composite/AspNet/Razor/CompositeC1WebPage.cs | 2 +- .../Commands/IConsoleCommandHandler.cs | 2 +- Composite/C1Console/Security/EntityToken.cs | 2 +- .../BuildinGlobalSettingsProvider.cs | 2 +- .../Configuration/GlobalSettingsFacade.cs | 2 +- Composite/Core/Log.cs | 28 +++++++++---------- .../DllPackageFragmentInstaller.cs | 2 +- .../PageTemplates/IPageTemplateProvider.cs | 2 +- .../PageTemplates/PageTemplateDescriptor.cs | 2 +- .../Core/PageTemplates/PageTemplateFacade.cs | 2 +- .../Core/ResourceSystem/LocalizationFiles.cs | 4 +-- Composite/Core/Routing/PageUrlData.cs | 2 +- .../ApplicationLevelEventHandlers.cs | 2 +- .../IDataRenderingResponseHandler.cs | 2 +- .../RenderingResponseHandlerFacade.cs | 4 +-- Composite/Core/Xml/Namespaces.cs | 4 +-- Composite/Core/Xml/XhtmlDocument.cs | 4 +-- Composite/Data/AutoUpdatebleAttribute.cs | 2 +- Composite/Data/DataConnection.cs | 10 +++---- Composite/Data/DataEntityToken.cs | 2 +- Composite/Data/DataEvents.cs | 18 ++++++------ Composite/Data/DataReference.cs | 4 +-- .../Data/DynamicTypes/DataTypeDescriptor.cs | 6 ++-- Composite/Data/DynamicTypes/StoreFieldType.cs | 2 +- Composite/Data/IData.cs | 2 +- Composite/Data/IDataReference.cs | 2 +- Composite/Data/PageNode.cs | 2 +- Composite/Data/PublicationScope.cs | 2 +- Composite/Data/SitemapNavigator.cs | 2 +- Composite/Data/Streams/IFileStreamManager.cs | 4 +-- Composite/Data/Types/IImageFile.cs | 2 +- Composite/Data/Types/IMediaFile.cs | 2 +- Composite/Data/Types/IMediaFileFolder.cs | 2 +- Composite/Data/Types/IPage.cs | 2 +- Composite/Data/Types/IUser.cs | 2 +- Composite/Data/Types/IUserGroup.cs | 2 +- .../Data/Types/IUserUserGroupRelation.cs | 2 +- .../FunctionParameterIgnoreAttribute.cs | 4 +-- .../Html/Template/CommonMetaTagsFunction.cs | 4 +-- .../ConfigBasedGlobalSettingsProvider.cs | 2 +- .../PerformanceNames.cs | 4 +-- .../MasterPages/MasterPageBase.cs | 4 +-- Composite/Properties/AssemblyInfo.cs | 12 ++++---- .../Composite/DebugBuild.Composite.config | 2 +- .../Composite/ReleaseBuild.Composite.config | 2 +- .../content/branding/about-company.inc | 2 +- ...e.Plugins.PackageElementProvider.en-us.xml | 2 +- ...posite.Plugins.StandardFunctions.en-us.xml | 2 +- Website/Composite/ping.ashx | 2 +- .../FormsControls/GenerateDynamicSchemas.aspx | 2 +- Website/Composite/schemas/Trees/Tree.xsd | 2 +- .../scripts/source/top/core/Client.js | 2 +- .../scripts/source/top/core/Installation.js | 4 +-- .../scripts/source/top/core/Prism.js | 2 +- Website/DebugBuild.Web.config | 2 +- Website/ReleaseBuild.Web.config | 2 +- Website/robots.txt | 2 +- 59 files changed, 104 insertions(+), 104 deletions(-) diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PackageElementProvider/ViewAvailablePackageInfoWorkflowWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PackageElementProvider/ViewAvailablePackageInfoWorkflowWorkflow.cs index beb8a44218..c5fe1ff159 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PackageElementProvider/ViewAvailablePackageInfoWorkflowWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PackageElementProvider/ViewAvailablePackageInfoWorkflowWorkflow.cs @@ -125,7 +125,7 @@ private string GetDocumentTitle(PackageDescription packageDescription) { // Valid package names: // "Composite.Community.Versioning" - // "Composite C1 3.0" + // "Orckestra CMS 3.0" string name = packageDescription.Name.Trim(); string documentTitle = name; diff --git a/Composite.Workflows/Properties/AssemblyInfo.cs b/Composite.Workflows/Properties/AssemblyInfo.cs index ce7907a1c0..3e4a4d6023 100644 --- a/Composite.Workflows/Properties/AssemblyInfo.cs +++ b/Composite.Workflows/Properties/AssemblyInfo.cs @@ -8,9 +8,9 @@ [assembly: AssemblyTitle("Composite.Workflows")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Composite A/S")] -[assembly: AssemblyProduct("Composite C1")] -[assembly: AssemblyCopyright("Copyright © Composite A/S 2016")] +[assembly: AssemblyCompany("Orckestra Inc")] +[assembly: AssemblyProduct("Orckestra CMS")] +[assembly: AssemblyCopyright("Copyright © Orckestra Inc 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Composite/AspNet/Razor/CompositeC1WebPage.cs b/Composite/AspNet/Razor/CompositeC1WebPage.cs index 0e468a38d8..174cb6924f 100644 --- a/Composite/AspNet/Razor/CompositeC1WebPage.cs +++ b/Composite/AspNet/Razor/CompositeC1WebPage.cs @@ -10,7 +10,7 @@ namespace Composite.AspNet.Razor { /// - /// Defines a composite C1 razor control + /// Defines a Orckestra CMS razor control /// public abstract class CompositeC1WebPage : WebPage, IDisposable { diff --git a/Composite/C1Console/Commands/IConsoleCommandHandler.cs b/Composite/C1Console/Commands/IConsoleCommandHandler.cs index 653f6e95b5..f3a005f765 100644 --- a/Composite/C1Console/Commands/IConsoleCommandHandler.cs +++ b/Composite/C1Console/Commands/IConsoleCommandHandler.cs @@ -4,7 +4,7 @@ namespace Composite.C1Console.Commands { /// - /// Handles hash based deep links to Composite C1 console (/Composite/top.aspx#<command name>;<command payload> ) + /// Handles hash based deep links to Orckestra CMS console (/Composite/top.aspx#<command name>;<command payload> ) /// [CustomFactory(typeof(ConsoleCommandHandlerCustomFactory))] public interface IConsoleCommandHandler diff --git a/Composite/C1Console/Security/EntityToken.cs b/Composite/C1Console/Security/EntityToken.cs index eb6a3d8619..ef0707b57c 100644 --- a/Composite/C1Console/Security/EntityToken.cs +++ b/Composite/C1Console/Security/EntityToken.cs @@ -26,7 +26,7 @@ public object Deserialize(string serializedObject) /// - /// EntityToken is used through out Composite C1 to describe artifacts that can have security settings. Also see . + /// EntityToken is used through out Orckestra CMS to describe artifacts that can have security settings. Also see . /// /// /// When subclassing this class and adding properties that have an impack when identity (equiallity) diff --git a/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs b/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs index f2d3a02cfe..78fb1393bc 100644 --- a/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs +++ b/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs @@ -8,7 +8,7 @@ namespace Composite.Core.Configuration.BuildinPlugins.GlobalSettingsProvider { internal sealed class BuildinGlobalSettingsProvider : IGlobalSettingsProvider { - private string _applicationName = "Composite C1"; + private string _applicationName = "Orckestra CMS"; private string _applicationShortName = "C1"; private string _brandedVersionAssemblySource = "Composite"; private string _configurationDirectory = "~"; diff --git a/Composite/Core/Configuration/GlobalSettingsFacade.cs b/Composite/Core/Configuration/GlobalSettingsFacade.cs index a05d7f63a7..185d97a553 100644 --- a/Composite/Core/Configuration/GlobalSettingsFacade.cs +++ b/Composite/Core/Configuration/GlobalSettingsFacade.cs @@ -440,7 +440,7 @@ public static bool OnlyTranslateWhenApproved /// /// The maximum number of characters the path to the application root (like 'C:\InetPub\MySite') can contain. - /// Composite C1 create files below this path, some of which have very long paths - if the root path is long enough the combined length + /// Orckestra CMS create files below this path, some of which have very long paths - if the root path is long enough the combined length /// can exceed a limitation in Microsoft Windows - see http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#paths /// public static int MaximumRootPathLength diff --git a/Composite/Core/Log.cs b/Composite/Core/Log.cs index e977a093fc..2d315068e9 100644 --- a/Composite/Core/Log.cs +++ b/Composite/Core/Log.cs @@ -7,12 +7,12 @@ namespace Composite.Core { /// - /// Provide write access to the Composite C1 log. Note that 'verbose' messages are typically only shown in run-time log viewers. + /// Provide write access to the Orckestra CMS log. Note that 'verbose' messages are typically only shown in run-time log viewers. /// public static class Log { /// - /// Logs a 'information' message to the Composite C1 log. + /// Logs a 'information' message to the Orckestra CMS log. /// /// Title of log message /// Message to log @@ -24,7 +24,7 @@ public static void LogInformation(string title, string message) /// - /// Logs a 'information' message to the Composite C1 log. + /// Logs a 'information' message to the Orckestra CMS log. /// /// Title of log message /// Message to log in a String.Format() style using {0} etc. @@ -38,7 +38,7 @@ public static void LogInformation(string title, string messageFormat, params obj /// - /// Logs a 'verbose' message to the Composite C1 log. Verbose messages are typically only shown in developer log viewers. + /// Logs a 'verbose' message to the Orckestra CMS log. Verbose messages are typically only shown in developer log viewers. /// /// Title of log message /// Message to log @@ -50,7 +50,7 @@ public static void LogVerbose(string title, string message) /// - /// Logs a 'verbose' message to the Composite C1 log. + /// Logs a 'verbose' message to the Orckestra CMS log. /// /// Title of log message /// Message to log in a String.Format() style using {0} etc. @@ -64,7 +64,7 @@ public static void LogVerbose(string title, string messageFormat, params object[ /// - /// Logs a 'warning' message to the Composite C1 log. + /// Logs a 'warning' message to the Orckestra CMS log. /// /// Title of log message /// Message to log @@ -76,7 +76,7 @@ public static void LogWarning(string title, string message) /// - /// Logs a 'warning' message to the Composite C1 log. + /// Logs a 'warning' message to the Orckestra CMS log. /// /// Title of log message /// Message to log in a String.Format() style using {0} etc. @@ -90,7 +90,7 @@ public static void LogWarning(string title, string messageFormat, params object[ /// - /// Logs a 'verbose' message to the Composite C1 log. + /// Logs a 'verbose' message to the Orckestra CMS log. /// /// Title of log message /// Exception to log @@ -102,7 +102,7 @@ public static void LogWarning(string title, Exception exception) /// - /// Logs a 'error' message to the Composite C1 log. + /// Logs a 'error' message to the Orckestra CMS log. /// /// Title of log message /// Message to log @@ -114,7 +114,7 @@ public static void LogError(string title, string message) /// - /// Logs a 'error' message to the Composite C1 log. + /// Logs a 'error' message to the Orckestra CMS log. /// /// Title of log message /// Message to log in a String.Format() style using {0} etc. @@ -128,7 +128,7 @@ public static void LogError(string title, string messageFormat, params object[] /// - /// Logs a 'error' message to the Composite C1 log. + /// Logs a 'error' message to the Orckestra CMS log. /// /// Title of log message /// Exception to log @@ -140,7 +140,7 @@ public static void LogError(string title, Exception exception) /// - /// Logs a 'critical' message to the Composite C1 log. You should only use 'critical' when a major system failure occur. + /// Logs a 'critical' message to the Orckestra CMS log. You should only use 'critical' when a major system failure occur. /// /// Title of log message /// Message to log @@ -152,7 +152,7 @@ public static void LogCritical(string title, string message) /// - /// Logs a 'critical' message to the Composite C1 log. You should only use 'critical' when a major system failure occur. + /// Logs a 'critical' message to the Orckestra CMS log. You should only use 'critical' when a major system failure occur. /// /// Title of log message /// Message to log in a String.Format() style using {0} etc. @@ -166,7 +166,7 @@ public static void LogCritical(string title, string messageFormat, params object /// - /// Logs a 'critical' message to the Composite C1 log. You should only use 'critical' when a major system failure occur. + /// Logs a 'critical' message to the Orckestra CMS log. You should only use 'critical' when a major system failure occur. /// /// Title of log message /// Exception to log diff --git a/Composite/Core/PackageSystem/PackageFragmentInstallers/DllPackageFragmentInstaller.cs b/Composite/Core/PackageSystem/PackageFragmentInstallers/DllPackageFragmentInstaller.cs index 6b41b83a54..50f307fe50 100644 --- a/Composite/Core/PackageSystem/PackageFragmentInstallers/DllPackageFragmentInstaller.cs +++ b/Composite/Core/PackageSystem/PackageFragmentInstallers/DllPackageFragmentInstaller.cs @@ -403,7 +403,7 @@ public void AddRedirectsForAssembly(AssemblyName assemblyName) - + ", assemblyName.Name, publicKeyToken, newTargetVersionStr)).Elements().Single()); diff --git a/Composite/Core/PageTemplates/IPageTemplateProvider.cs b/Composite/Core/PageTemplates/IPageTemplateProvider.cs index a0e174dc49..4903e2f6a2 100644 --- a/Composite/Core/PageTemplates/IPageTemplateProvider.cs +++ b/Composite/Core/PageTemplates/IPageTemplateProvider.cs @@ -19,7 +19,7 @@ public interface IPageTemplateProvider IEnumerable GetPageTemplates(); /// - /// Factory that give Composite C1 a IPageLayouter capable of rendering a Composite C1 page with the specified layout ID. + /// Factory that give Orckestra CMS a IPageLayouter capable of rendering a Orckestra CMS page with the specified layout ID. /// The factory will be called for each individual page rendering /// /// diff --git a/Composite/Core/PageTemplates/PageTemplateDescriptor.cs b/Composite/Core/PageTemplates/PageTemplateDescriptor.cs index 8451c22489..1732cbb497 100644 --- a/Composite/Core/PageTemplates/PageTemplateDescriptor.cs +++ b/Composite/Core/PageTemplates/PageTemplateDescriptor.cs @@ -6,7 +6,7 @@ namespace Composite.Core.PageTemplates { /// - /// Describes a page layout to the Composite C1 core so it may set up editing UI + /// Describes a page layout to the Orckestra CMS core so it may set up editing UI /// public class PageTemplateDescriptor { diff --git a/Composite/Core/PageTemplates/PageTemplateFacade.cs b/Composite/Core/PageTemplates/PageTemplateFacade.cs index 7a53615eb7..14a8b02e88 100644 --- a/Composite/Core/PageTemplates/PageTemplateFacade.cs +++ b/Composite/Core/PageTemplates/PageTemplateFacade.cs @@ -63,7 +63,7 @@ public static IPageRenderer BuildPageRenderer(Guid pageTemplateId) { var provider = PageTemplateProviderRegistry.GetProviderByTemplateId(pageTemplateId); - Verify.IsNotNull(provider, "Failed to get page template with id '{0}'. The template may contain errors preventing it to compile. Check the Composite C1 log for possible compilation errors.", pageTemplateId); + Verify.IsNotNull(provider, "Failed to get page template with id '{0}'. The template may contain errors preventing it to compile. Check the Orckestra CMS log for possible compilation errors.", pageTemplateId); return provider.BuildPageRenderer(pageTemplateId); } diff --git a/Composite/Core/ResourceSystem/LocalizationFiles.cs b/Composite/Core/ResourceSystem/LocalizationFiles.cs index 8a650b7b9a..2074fa45cd 100644 --- a/Composite/Core/ResourceSystem/LocalizationFiles.cs +++ b/Composite/Core/ResourceSystem/LocalizationFiles.cs @@ -3428,7 +3428,7 @@ public static class Composite_Plugins_PackageElementProvider { public static string AddPackageSource_Step1_UrlHelp=>T("AddPackageSource.Step1.UrlHelp"); ///"The entered text was not a valid URL" public static string AddPackageSource_Step1_UrlNotValid=>T("AddPackageSource.Step1.UrlNotValid"); -///"The server is not a Composite C1 package server" +///"The server is not a Orckestra CMS package server" public static string AddPackageSource_Step1_UrlNonPackageServer=>T("AddPackageSource.Step1.UrlNonPackageServer"); ///"Add Package Server Source" public static string AddPackageSource_Step2_LayoutLabel=>T("AddPackageSource.Step2.LayoutLabel"); @@ -4826,7 +4826,7 @@ public static class Composite_Plugins_StandardFunctions { public static string Composite_Web_Html_Template_CommonMetaTags_param_Designer_help=>T("Composite.Web.Html.Template.CommonMetaTags.param.Designer.help"); ///"Show generator" public static string Composite_Web_Html_Template_CommonMetaTags_param_ShowGenerator_label=>T("Composite.Web.Html.Template.CommonMetaTags.param.ShowGenerator.label"); -///"Show the world you support Composite C1 - free open source!" +///"Show the world you support Orckestra CMS - free open source!" public static string Composite_Web_Html_Template_CommonMetaTags_param_ShowGenerator_help=>T("Composite.Web.Html.Template.CommonMetaTags.param.ShowGenerator.help"); ///"Appends a lang='(language code)' attribute the the parent element, reflecting the language of the current page. You can put this just below the <html /> tag." public static string Composite_Web_Html_Template_LangAttribute_description=>T("Composite.Web.Html.Template.LangAttribute.description"); diff --git a/Composite/Core/Routing/PageUrlData.cs b/Composite/Core/Routing/PageUrlData.cs index 6d6f7bb3b7..fc0eea07a6 100644 --- a/Composite/Core/Routing/PageUrlData.cs +++ b/Composite/Core/Routing/PageUrlData.cs @@ -7,7 +7,7 @@ namespace Composite.Core.Routing { /// - /// Information stored in a Composite C1 page url + /// Information stored in a Orckestra CMS page url /// public class PageUrlData { diff --git a/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs b/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs index 78804628f0..7deb59db8e 100644 --- a/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs +++ b/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs @@ -24,7 +24,7 @@ namespace Composite.Core.WebClient { /// - /// ASP.NET Application level logic. This class primarily interact between Composite C1 and the ASP.NET Application. + /// ASP.NET Application level logic. This class primarily interact between Orckestra CMS and the ASP.NET Application. /// Most of the members on this class is not documented, except for those which developers may find useful to interact with. /// public static class ApplicationLevelEventHandlers diff --git a/Composite/Core/WebClient/Renderings/Plugins/RenderingResponseHandler/IDataRenderingResponseHandler.cs b/Composite/Core/WebClient/Renderings/Plugins/RenderingResponseHandler/IDataRenderingResponseHandler.cs index 109993ab3e..b630306374 100644 --- a/Composite/Core/WebClient/Renderings/Plugins/RenderingResponseHandler/IDataRenderingResponseHandler.cs +++ b/Composite/Core/WebClient/Renderings/Plugins/RenderingResponseHandler/IDataRenderingResponseHandler.cs @@ -4,7 +4,7 @@ namespace Composite.Core.WebClient.Renderings.Plugins.RenderingResponseHandler { /// - /// Composite C1 allow you to build a RenderingResponseHandler plug-in. It enables developers to intercept + /// Orckestra CMS allow you to build a RenderingResponseHandler plug-in. It enables developers to intercept /// page and media requests and control if the request should be accepted or redirected and if the rendered /// resource is allowed to be publicly cached. /// diff --git a/Composite/Core/WebClient/Renderings/RenderingResponseHandlerFacade.cs b/Composite/Core/WebClient/Renderings/RenderingResponseHandlerFacade.cs index a08aa600a5..6ac18c08ce 100644 --- a/Composite/Core/WebClient/Renderings/RenderingResponseHandlerFacade.cs +++ b/Composite/Core/WebClient/Renderings/RenderingResponseHandlerFacade.cs @@ -5,7 +5,7 @@ namespace Composite.Core.WebClient.Renderings { /// /// Pass information about a request through all - /// plugins registered on the Composite C1 site. Use this if you are handling raw page / media http requests yourself. + /// plugins registered on the Orckestra CMS site. Use this if you are handling raw page / media http requests yourself. /// /// public static class RenderingResponseHandlerFacade @@ -18,7 +18,7 @@ public static class RenderingResponseHandlerFacade /// /// Pass information about a request through all - /// plugins registered on the Composite C1 site. The resulting define how you should treat the request. + /// plugins registered on the Orckestra CMS site. The resulting define how you should treat the request. /// /// The data being rendered. This can be and . /// A object detailing what should happen to the user request. Returning null means no special handling should be done (request should continue). diff --git a/Composite/Core/Xml/Namespaces.cs b/Composite/Core/Xml/Namespaces.cs index 3465b17811..1fd4bf24fe 100644 --- a/Composite/Core/Xml/Namespaces.cs +++ b/Composite/Core/Xml/Namespaces.cs @@ -72,7 +72,7 @@ static Namespaces() public static XNamespace Localization10 { get; private set; } /// - /// Namespace for ASP.NET Web Forms in Composite C1 pages: http://www.composite.net/ns/asp.net/controls + /// Namespace for ASP.NET Web Forms in Orckestra CMS pages: http://www.composite.net/ns/asp.net/controls /// public static XNamespace AspNetControls { get; private set; } @@ -92,7 +92,7 @@ static Namespaces() public static XNamespace XmlNs { get; private set; } /// - /// Namespace for XHTML documents in Composite C1: http://www.w3.org/1999/xhtml + /// Namespace for XHTML documents in Orckestra CMS: http://www.w3.org/1999/xhtml /// public static XNamespace Xhtml { get; private set; } diff --git a/Composite/Core/Xml/XhtmlDocument.cs b/Composite/Core/Xml/XhtmlDocument.cs index 3420fd289c..4f31b4a8cd 100644 --- a/Composite/Core/Xml/XhtmlDocument.cs +++ b/Composite/Core/Xml/XhtmlDocument.cs @@ -12,10 +12,10 @@ namespace Composite.Core.Xml { /// - /// Represents an XHTML Document inside Composite C1. + /// Represents an XHTML Document inside Orckestra CMS. /// /// This structure can contain both head elements and body elements (content) and XhtmlDocuments that are being rendered - /// can be nested within each other. The Composite C1 core will normalize such a nested structure when rendering a page, ensuring head elementsa flow to the top level + /// can be nested within each other. The Orckestra CMS core will normalize such a nested structure when rendering a page, ensuring head elementsa flow to the top level /// document and body content is left, ultimately yielding one complete and correctly structured xhtml page. /// [XhtmlDocumentConverter] diff --git a/Composite/Data/AutoUpdatebleAttribute.cs b/Composite/Data/AutoUpdatebleAttribute.cs index 16726d5700..c5bb54909a 100644 --- a/Composite/Data/AutoUpdatebleAttribute.cs +++ b/Composite/Data/AutoUpdatebleAttribute.cs @@ -5,7 +5,7 @@ namespace Composite.Data { /// /// IData types decorated with this attribute will be have their store auto created and updated if the interface changes. - /// You should use this attribute for data types that Composite C1 should be able to auto support via data providers. + /// You should use this attribute for data types that Orckestra CMS should be able to auto support via data providers. /// [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)] public sealed class AutoUpdatebleAttribute : Attribute diff --git a/Composite/Data/DataConnection.cs b/Composite/Data/DataConnection.cs index f0a3f850a3..0db2d7246f 100644 --- a/Composite/Data/DataConnection.cs +++ b/Composite/Data/DataConnection.cs @@ -8,7 +8,7 @@ namespace Composite.Data { /// - /// Represents a connection to the Composite C1 data system. + /// Represents a connection to the Orckestra CMS data system. /// /// /// Here is an example of how to use it @@ -61,7 +61,7 @@ public void DisableServices() /// Creates a new instance inheriting the /// and locale set on the call stack. When outside an existing scope this default to PublicationScope,Published and the /// default language on the website. You should use this constructure unless you need to force data to come from an alternative - /// scope. can be used to access the Composite C1 storage. + /// scope. can be used to access the Orckestra CMS storage. /// /// /// Here is an example of how to use it @@ -88,7 +88,7 @@ public DataConnection() /// /// Creates a new instance with the given - /// and current (or default) locale. can be used to access the Composite C1 storage. + /// and current (or default) locale. can be used to access the Orckestra CMS storage. /// /// The data should be read from. /// @@ -118,7 +118,7 @@ public DataConnection(PublicationScope scope) /// /// Creates a new instance with current or default - /// and the given . can be used to access the Composite C1 storage. + /// and the given . can be used to access the Orckestra CMS storage. /// /// The desired locale. This should be one of the locale found in /// @@ -146,7 +146,7 @@ public DataConnection(CultureInfo locale) /// /// Creates a new instance with the given - /// and the given . can be used to access the Composite C1 storage. + /// and the given . can be used to access the Orckestra CMS storage. /// /// The data should be read from. /// The desired locale. This should be one of the locale found in diff --git a/Composite/Data/DataEntityToken.cs b/Composite/Data/DataEntityToken.cs index b0454bbc77..778116f9c5 100644 --- a/Composite/Data/DataEntityToken.cs +++ b/Composite/Data/DataEntityToken.cs @@ -9,7 +9,7 @@ namespace Composite.Data { /// - /// EntityToken that represents a C1 Data item. EntityToken is used through out Composite C1 to describe artifacts that can have security settings and be navigated and this class make it easy + /// EntityToken that represents a C1 Data item. EntityToken is used through out Orckestra CMS to describe artifacts that can have security settings and be navigated and this class make it easy /// to move between data items and EntityToken. /// [SecurityAncestorProvider(typeof(DataSecurityAncestorProvider))] diff --git a/Composite/Data/DataEvents.cs b/Composite/Data/DataEvents.cs index bee1d08b19..dc85c2ea89 100644 --- a/Composite/Data/DataEvents.cs +++ b/Composite/Data/DataEvents.cs @@ -6,10 +6,10 @@ namespace Composite.Data { /// - /// This class contains all the event fired by Composite C1 when changes are made to data items. + /// This class contains all the event fired by Orckestra CMS when changes are made to data items. /// /// Use to catch any data change event, including events originating from other servers in a load balance setup - /// or changes made directly to a store (which Composite C1 can detect). This event do not contain details about the specific data item changed and is raised after the fact. + /// or changes made directly to a store (which Orckestra CMS can detect). This event do not contain details about the specific data item changed and is raised after the fact. /// /// Use the more detailed operations to catch data events that happen in the current website process. The 'OnBefore' events enable you to manipulate data before they are stored. /// The 'OnAfter' events let you react to data changes in detail, for instance updating a cache. @@ -55,7 +55,7 @@ public static class DataEvents where TData : class, IData { /// - /// This event is fired just before a data item is added to the Composite C1 data store. + /// This event is fired just before a data item is added to the Orckestra CMS data store. /// See /// /// @@ -96,7 +96,7 @@ public static event DataEventHandler OnBeforeAdd /// - /// This event is fired just after a data item has been added to the Composite C1 data store. + /// This event is fired just after a data item has been added to the Orckestra CMS data store. /// See /// /// @@ -137,7 +137,7 @@ public static event DataEventHandler OnAfterAdd /// - /// This event is fired just before a data item is updated in the Composite C1 data store. + /// This event is fired just before a data item is updated in the Orckestra CMS data store. /// See /// /// @@ -182,7 +182,7 @@ public static event DataEventHandler OnBeforeUpdate /// - /// This event is fired just after a data item has been updated in the Composite C1 data store. + /// This event is fired just after a data item has been updated in the Orckestra CMS data store. /// See /// /// @@ -227,7 +227,7 @@ public static event DataEventHandler OnAfterUpdate /// - /// This event is fired after a data item has been deleted from the Composite C1 data store. + /// This event is fired after a data item has been deleted from the Orckestra CMS data store. /// See /// /// @@ -270,7 +270,7 @@ public static event DataEventHandler OnDeleted /// - /// This event is fired after changes has happened to the Composite C1 data store. This may be atomic actions or a larger change to the underlying + /// This event is fired after changes has happened to the Orckestra CMS data store. This may be atomic actions or a larger change to the underlying /// data store. The class describe the change in broad terms, including a flag indicating is detailed data /// event have been raised or not. /// @@ -358,7 +358,7 @@ public static event DataEventHandler OnNew /// Fire the event that signals that data in an external store has changed. /// /// - /// You should NOT fire this event if you do data changes through the Composite C1 data API since events will already be handled for you in this case. + /// You should NOT fire this event if you do data changes through the Orckestra CMS data API since events will already be handled for you in this case. /// /// Use this method if you are responsible for flushing cached data originating from a store not fully managed by the local website process. /// diff --git a/Composite/Data/DataReference.cs b/Composite/Data/DataReference.cs index 9267b0eba9..52c7bd5c97 100644 --- a/Composite/Data/DataReference.cs +++ b/Composite/Data/DataReference.cs @@ -7,7 +7,7 @@ namespace Composite.Data { /// - /// Represents a reference to a Composite C1 IData item. Unlike this class signals + /// Represents a reference to a Orckestra CMS IData item. Unlike this class signals /// that a data reference need not be set for this to be in a valid state. /// /// The C1 Data Type () being referenced @@ -30,7 +30,7 @@ public NullableDataReference(object keyValue) /// - /// Represents a reference to a Composite C1 IData item. + /// Represents a reference to a Orckestra CMS IData item. /// /// The C1 Data Type () being referenced [DataReferenceConverter] diff --git a/Composite/Data/DynamicTypes/DataTypeDescriptor.cs b/Composite/Data/DynamicTypes/DataTypeDescriptor.cs index b44c9935ab..af1b8cda58 100644 --- a/Composite/Data/DynamicTypes/DataTypeDescriptor.cs +++ b/Composite/Data/DynamicTypes/DataTypeDescriptor.cs @@ -18,7 +18,7 @@ namespace Composite.Data.DynamicTypes { /// - /// Describes a data type in Composite C1 + /// Describes a data type in Orckestra CMS /// [DebuggerDisplay("Type name = {Namespace + '.' + Name}")] public class DataTypeDescriptor @@ -452,7 +452,7 @@ public List DataAssociations /// - /// True when the data type is associated to Composite C1 pages as an agregation + /// True when the data type is associated to Orckestra CMS pages as an agregation /// public bool IsPageFolderDataType { @@ -465,7 +465,7 @@ public bool IsPageFolderDataType /// - /// True when the data type is associated to Composite C1 pages as an composition + /// True when the data type is associated to Orckestra CMS pages as an composition /// public bool IsPageMetaDataType { diff --git a/Composite/Data/DynamicTypes/StoreFieldType.cs b/Composite/Data/DynamicTypes/StoreFieldType.cs index f7102066e7..0ca56a05ec 100644 --- a/Composite/Data/DynamicTypes/StoreFieldType.cs +++ b/Composite/Data/DynamicTypes/StoreFieldType.cs @@ -8,7 +8,7 @@ namespace Composite.Data.DynamicTypes { /// - /// Describe a field on a Composite C1 data type, see . + /// Describe a field on a Orckestra CMS data type, see . /// [Serializable()] public sealed class StoreFieldType diff --git a/Composite/Data/IData.cs b/Composite/Data/IData.cs index aae5a856f2..31aea23f00 100644 --- a/Composite/Data/IData.cs +++ b/Composite/Data/IData.cs @@ -4,7 +4,7 @@ namespace Composite.Data { /// - /// Base interface for data types in Composite C1. + /// Base interface for data types in Orckestra CMS. /// [SerializerHandler(typeof(DataSerializerHandler))] public interface IData diff --git a/Composite/Data/IDataReference.cs b/Composite/Data/IDataReference.cs index 7e635bdc61..3a87add5e9 100644 --- a/Composite/Data/IDataReference.cs +++ b/Composite/Data/IDataReference.cs @@ -6,7 +6,7 @@ namespace Composite.Data { /// - /// Represents a reference to a Composite C1 IData item. See . + /// Represents a reference to a Orckestra CMS IData item. See . /// public interface IDataReference { diff --git a/Composite/Data/PageNode.cs b/Composite/Data/PageNode.cs index a6c0b7968d..1c0747035c 100644 --- a/Composite/Data/PageNode.cs +++ b/Composite/Data/PageNode.cs @@ -11,7 +11,7 @@ namespace Composite.Data { /// - /// Represents a page in the Composite C1 sitemap hierarchy. + /// Represents a page in the Orckestra CMS sitemap hierarchy. /// public class PageNode { diff --git a/Composite/Data/PublicationScope.cs b/Composite/Data/PublicationScope.cs index 69dfaa42bb..e884408a39 100644 --- a/Composite/Data/PublicationScope.cs +++ b/Composite/Data/PublicationScope.cs @@ -8,7 +8,7 @@ namespace Composite.Data /// /// Define the scope of data in relation to publication status. Data which support publication should always be maintained /// in the “Unpublihed” scope, while reading data on the public website should always be done in the “Published” scope. - /// Correct setting of the PublicationScope is typically handled by Composite C1 and should in general not be changed by developers. + /// Correct setting of the PublicationScope is typically handled by Orckestra CMS and should in general not be changed by developers. /// Setting an explicit PublicationScope is typically only needed on new service end-points or /// if specific features relating to data updating / publication is desired. /// See diff --git a/Composite/Data/SitemapNavigator.cs b/Composite/Data/SitemapNavigator.cs index 2897716718..486b06bf02 100644 --- a/Composite/Data/SitemapNavigator.cs +++ b/Composite/Data/SitemapNavigator.cs @@ -8,7 +8,7 @@ namespace Composite.Data { /// - /// Provide access to the Composite C1 sitemap structure and primary page attributes. + /// Provide access to the Orckestra CMS sitemap structure and primary page attributes. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Sitemap")] public class SitemapNavigator : ImplementationContainer diff --git a/Composite/Data/Streams/IFileStreamManager.cs b/Composite/Data/Streams/IFileStreamManager.cs index 63c32fbeb4..d4bb69eae7 100644 --- a/Composite/Data/Streams/IFileStreamManager.cs +++ b/Composite/Data/Streams/IFileStreamManager.cs @@ -34,12 +34,12 @@ public enum FileChangeType /// (like for a custom Media File Provider) expose access to stream reads/writes by annotating /// the class implementing with the attribute, /// passing the type of a as attribute parameter. - /// Composite C1 will, via the attribute on the , get the type responsible for stream reads/writes. + /// Orckestra CMS will, via the attribute on the , get the type responsible for stream reads/writes. /// /// The class implementing this interface is expected to provide read/write access to the file store being introduced by a file oriented File Provider. /// /// - /// Here is an example of how to inform Composite C1 about IFileStreamManager + /// Here is an example of how to inform Orckestra CMS about IFileStreamManager /// /// [FileStreamManager(typeof(MyFileStreamManager))] /// public abstract class SomeFile : IFile diff --git a/Composite/Data/Types/IImageFile.cs b/Composite/Data/Types/IImageFile.cs index 8bb541d8df..ff0935c6b5 100644 --- a/Composite/Data/Types/IImageFile.cs +++ b/Composite/Data/Types/IImageFile.cs @@ -4,7 +4,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a image media file in Composite C1. This can be used to query images through a . + /// This data interface represents a image media file in Orckestra CMS. This can be used to query images through a . /// [Title("C1 Image File")] [ImmutableTypeId("{BF54E59A-0EBC-4162-95B9-C46EE271C7A9}")] diff --git a/Composite/Data/Types/IMediaFile.cs b/Composite/Data/Types/IMediaFile.cs index d4da9c7468..fe41550933 100644 --- a/Composite/Data/Types/IMediaFile.cs +++ b/Composite/Data/Types/IMediaFile.cs @@ -6,7 +6,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a media file in Composite C1. This can be used to query media through a . + /// This data interface represents a media file in Orckestra CMS. This can be used to query media through a . /// [Title("C1 Media File")] [KeyPropertyName("KeyPath")] diff --git a/Composite/Data/Types/IMediaFileFolder.cs b/Composite/Data/Types/IMediaFileFolder.cs index 8434ef481d..9db818a675 100644 --- a/Composite/Data/Types/IMediaFileFolder.cs +++ b/Composite/Data/Types/IMediaFileFolder.cs @@ -6,7 +6,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a media folder in Composite C1. This can be used to query media folders through a . + /// This data interface represents a media folder in Orckestra CMS. This can be used to query media folders through a . /// [Title("C1 Media Folder")] [KeyPropertyName("KeyPath")] diff --git a/Composite/Data/Types/IPage.cs b/Composite/Data/Types/IPage.cs index a9613af014..5edf997c1e 100644 --- a/Composite/Data/Types/IPage.cs +++ b/Composite/Data/Types/IPage.cs @@ -11,7 +11,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a page in Composite C1. This can be used to query pages through a . + /// This data interface represents a page in Orckestra CMS. This can be used to query pages through a . /// Note that a lot of page related tasks can be done with a . /// And any changes done through this interface and a should be done with care. /// diff --git a/Composite/Data/Types/IUser.cs b/Composite/Data/Types/IUser.cs index 576fe291d8..6564874330 100644 --- a/Composite/Data/Types/IUser.cs +++ b/Composite/Data/Types/IUser.cs @@ -9,7 +9,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a administrative user in Composite C1. This can be used to query users through a . + /// This data interface represents a administrative user in Orckestra CMS. This can be used to query users through a . /// [AutoUpdateble] [KeyPropertyName(nameof(Id))] diff --git a/Composite/Data/Types/IUserGroup.cs b/Composite/Data/Types/IUserGroup.cs index 49565dc7e3..3e74862104 100644 --- a/Composite/Data/Types/IUserGroup.cs +++ b/Composite/Data/Types/IUserGroup.cs @@ -7,7 +7,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a user group in Composite C1. This can be used to query user groups through a . + /// This data interface represents a user group in Orckestra CMS. This can be used to query user groups through a . /// [AutoUpdateble] [KeyPropertyName("Id")] diff --git a/Composite/Data/Types/IUserUserGroupRelation.cs b/Composite/Data/Types/IUserUserGroupRelation.cs index 8b77697177..a489ecabac 100644 --- a/Composite/Data/Types/IUserUserGroupRelation.cs +++ b/Composite/Data/Types/IUserUserGroupRelation.cs @@ -6,7 +6,7 @@ namespace Composite.Data.Types { /// - /// This data interface represents a user relation to a user group in Composite C1. This can be used to query user group members through a . + /// This data interface represents a user relation to a user group in Orckestra CMS. This can be used to query user group members through a . /// [AutoUpdateble] [KeyPropertyName(0, "UserId")] diff --git a/Composite/Functions/FunctionParameterIgnoreAttribute.cs b/Composite/Functions/FunctionParameterIgnoreAttribute.cs index eb937d2970..1683ac393b 100644 --- a/Composite/Functions/FunctionParameterIgnoreAttribute.cs +++ b/Composite/Functions/FunctionParameterIgnoreAttribute.cs @@ -3,12 +3,12 @@ namespace Composite.Functions { /// - /// Put this attribute on properties to make Composite C1 skip them when infering C1 Function parameters from a class. + /// Put this attribute on properties to make Orckestra CMS skip them when infering C1 Function parameters from a class. /// /// If you need a property on your class, but do not want this property to be part of the C1 Function signature use this attrobute. /// /// - /// Here is an example of how to use to make Composite C1 skip a property when infering parameters: + /// Here is an example of how to use to make Orckestra CMS skip a property when infering parameters: /// /// [FunctionParameterIgnore()] /// public int ItemCount { get; set; } diff --git a/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs b/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs index 64d6cce115..bcf4fec837 100644 --- a/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs +++ b/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs @@ -20,7 +20,7 @@ protected override IEnumerable StandardFunctio { get { - WidgetFunctionProvider showGeneratorWidget = StandardWidgetFunctions.GetBoolSelectorWidget("Yes, show Composite C1 support!", "No, please hide this..."); + WidgetFunctionProvider showGeneratorWidget = StandardWidgetFunctions.GetBoolSelectorWidget("Yes, show Orckestra CMS Foundation support!", "No, please hide this..."); yield return new StandardFunctionParameterProfile( "ContentType", @@ -73,7 +73,7 @@ public override object Execute(ParameterList parameters, FunctionContextContaine { metaTags.Add(new XElement(Namespaces.Xhtml + "meta", new XAttribute("name", "Generator"), - new XAttribute("content", "Composite C1 CMS - Free Open Source from http://composite.net/"))); + new XAttribute("content", "Orckestra CMS CMS - Free Open Source from http://composite.net/"))); } return metaTags; diff --git a/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs b/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs index 3e3a1dd824..7b12fb5132 100644 --- a/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs +++ b/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs @@ -339,7 +339,7 @@ public IGlobalSettingsProvider Assemble(IBuilderContext context, GlobalSettingsP internal sealed class ConfigBasedGlobalSettingsProviderData : GlobalSettingsProviderData { private const string _applicationNamePropertyName = "applicationName"; - [ConfigurationProperty(_applicationNamePropertyName, IsRequired = true, DefaultValue = "Composite C1")] + [ConfigurationProperty(_applicationNamePropertyName, IsRequired = true, DefaultValue = "Orckestra CMS")] public string ApplicationName { get { return (string)base[_applicationNamePropertyName]; } diff --git a/Composite/Plugins/Instrumentation/PerformanceCounterProviders/WindowsPerformanceCounterProvider/PerformanceNames.cs b/Composite/Plugins/Instrumentation/PerformanceCounterProviders/WindowsPerformanceCounterProvider/PerformanceNames.cs index 0e4a835e07..0ee052f6ff 100644 --- a/Composite/Plugins/Instrumentation/PerformanceCounterProviders/WindowsPerformanceCounterProvider/PerformanceNames.cs +++ b/Composite/Plugins/Instrumentation/PerformanceCounterProviders/WindowsPerformanceCounterProvider/PerformanceNames.cs @@ -4,8 +4,8 @@ namespace Composite.Plugins.Instrumentation.PerformanceCounterProviders.WindowsP { internal static class PerformanceNames { - public static string CategoryName { get { return "Composite C1"; } } - public static string CategoryDescription { get { return "Composite C1"; } } + public static string CategoryName { get { return "Orckestra CMS"; } } + public static string CategoryDescription { get { return "Orckestra CMS"; } } public static string SystemStartupCountName { get { return "SystemStartupCount"; } } public static string SystemStartupCountDescription { get { return "SystemStartupCount"; } } diff --git a/Composite/Plugins/PageTemplates/MasterPages/MasterPageBase.cs b/Composite/Plugins/PageTemplates/MasterPages/MasterPageBase.cs index 0cd24e6910..66d484b016 100644 --- a/Composite/Plugins/PageTemplates/MasterPages/MasterPageBase.cs +++ b/Composite/Plugins/PageTemplates/MasterPages/MasterPageBase.cs @@ -7,8 +7,8 @@ namespace Composite.Plugins.PageTemplates.MasterPages { /// - /// Base class for ASP.NET MasterPage classes in Composite C1. Inheriting from this bring common features like easy data and sitemap access. - /// This class is intended for use in shared MasterPages, to create a MasterPage based page template for Composite C1 use . + /// Base class for ASP.NET MasterPage classes in Orckestra CMS. Inheriting from this bring common features like easy data and sitemap access. + /// This class is intended for use in shared MasterPages, to create a MasterPage based page template for Orckestra CMS use . /// public abstract class MasterPageBase : MasterPage { diff --git a/Composite/Properties/AssemblyInfo.cs b/Composite/Properties/AssemblyInfo.cs index 8bfac26e19..dc7582e562 100644 --- a/Composite/Properties/AssemblyInfo.cs +++ b/Composite/Properties/AssemblyInfo.cs @@ -8,16 +8,16 @@ // associated with an assembly. #if !InternalBuild -[assembly: AssemblyTitle("Composite C1 5.2")] +[assembly: AssemblyTitle("Orckestra CMS 5.2")] #else -[assembly: AssemblyTitle("Composite C1 5.2 (Internal Build)")] +[assembly: AssemblyTitle("Orckestra CMS 5.2 (Internal Build)")] #endif -[assembly: AssemblyDescription("Composite C1 Core classes")] +[assembly: AssemblyDescription("Orckestra CMS Core classes")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Composite A/S")] -[assembly: AssemblyProduct("Composite C1")] -[assembly: AssemblyCopyright("Copyright Composite A/S 2016")] +[assembly: AssemblyCompany("Orckestra Inc")] +[assembly: AssemblyProduct("Orckestra CMS")] +[assembly: AssemblyCopyright("Copyright Orckestra Inc 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Website/App_Data/Composite/DebugBuild.Composite.config b/Website/App_Data/Composite/DebugBuild.Composite.config index 0a465c3148..6c0a50a453 100644 --- a/Website/App_Data/Composite/DebugBuild.Composite.config +++ b/Website/App_Data/Composite/DebugBuild.Composite.config @@ -68,7 +68,7 @@
diff --git a/Website/Composite/localization/Composite.Plugins.PackageElementProvider.en-us.xml b/Website/Composite/localization/Composite.Plugins.PackageElementProvider.en-us.xml index e5faf794bb..3a63807b32 100644 --- a/Website/Composite/localization/Composite.Plugins.PackageElementProvider.en-us.xml +++ b/Website/Composite/localization/Composite.Plugins.PackageElementProvider.en-us.xml @@ -142,7 +142,7 @@ - + diff --git a/Website/Composite/localization/Composite.Plugins.StandardFunctions.en-us.xml b/Website/Composite/localization/Composite.Plugins.StandardFunctions.en-us.xml index 13272cc30e..ab487dd5b1 100644 --- a/Website/Composite/localization/Composite.Plugins.StandardFunctions.en-us.xml +++ b/Website/Composite/localization/Composite.Plugins.StandardFunctions.en-us.xml @@ -272,7 +272,7 @@ - + diff --git a/Website/Composite/ping.ashx b/Website/Composite/ping.ashx index 07ed18332a..416be86ba3 100644 --- a/Website/Composite/ping.ashx +++ b/Website/Composite/ping.ashx @@ -29,7 +29,7 @@ public class PingTester : IHttpHandler return; } - context.Response.Write("This Composite C1 site has been initialized (info)\n\n"); + context.Response.Write("This Orckestra CMS site has been initialized (info)\n\n"); } IPHostEntry packageServerAddress; diff --git a/Website/Composite/schemas/FormsControls/GenerateDynamicSchemas.aspx b/Website/Composite/schemas/FormsControls/GenerateDynamicSchemas.aspx index d2b64811ab..f7170ca6e8 100644 --- a/Website/Composite/schemas/FormsControls/GenerateDynamicSchemas.aspx +++ b/Website/Composite/schemas/FormsControls/GenerateDynamicSchemas.aspx @@ -4,7 +4,7 @@ - Composite C1 Form UI Schemas + Orckestra CMS Form UI Schemas
diff --git a/Website/Composite/schemas/Trees/Tree.xsd b/Website/Composite/schemas/Trees/Tree.xsd index 1916930318..a6c0420423 100644 --- a/Website/Composite/schemas/Trees/Tree.xsd +++ b/Website/Composite/schemas/Trees/Tree.xsd @@ -78,7 +78,7 @@ - A Composite C1 data type + A Orckestra CMS data type diff --git a/Website/Composite/scripts/source/top/core/Client.js b/Website/Composite/scripts/source/top/core/Client.js index a89ed3f76d..2d857491b0 100644 --- a/Website/Composite/scripts/source/top/core/Client.js +++ b/Website/Composite/scripts/source/top/core/Client.js @@ -127,7 +127,7 @@ _Client.prototype = { }, /** - * Client qualified for the awesome Composite C1 experience? + * Client qualified for the awesome Orckestra CMS experience? * @return {boolean} */ qualifies: function () { diff --git a/Website/Composite/scripts/source/top/core/Installation.js b/Website/Composite/scripts/source/top/core/Installation.js index 6c6a4b23f7..50877c7000 100644 --- a/Website/Composite/scripts/source/top/core/Installation.js +++ b/Website/Composite/scripts/source/top/core/Installation.js @@ -8,7 +8,7 @@ function _Installation () { _Installation.prototype = { - /** Application Name like "Composite C1" + /** Application Name like "Orckestra CMS" * @type {string} */ applicationName: null, @@ -20,7 +20,7 @@ _Installation.prototype = { versionString: null, /** - * Human readable product version "Composite C1 1.2 SP2". + * Human readable product version "Orckestra CMS 1.2 SP2". * @type {string} */ versionPrettyString: null, diff --git a/Website/Composite/scripts/source/top/core/Prism.js b/Website/Composite/scripts/source/top/core/Prism.js index bedc7b1310..ccc25b69c1 100644 --- a/Website/Composite/scripts/source/top/core/Prism.js +++ b/Website/Composite/scripts/source/top/core/Prism.js @@ -1,7 +1,7 @@ /** * @class * Allows basic communication between C1 and the Prism host. - * The Composite C1 extension must be installed in Prism. + * The Orckestra CMS extension must be installed in Prism. */ function _Prism () {} _Prism.prototype = { diff --git a/Website/DebugBuild.Web.config b/Website/DebugBuild.Web.config index 39c90470f8..2ad1d3cd1d 100644 --- a/Website/DebugBuild.Web.config +++ b/Website/DebugBuild.Web.config @@ -1,5 +1,5 @@  - + diff --git a/Website/ReleaseBuild.Web.config b/Website/ReleaseBuild.Web.config index 5a5e95a0e2..12ef728d4a 100644 --- a/Website/ReleaseBuild.Web.config +++ b/Website/ReleaseBuild.Web.config @@ -1,6 +1,6 @@ - + diff --git a/Website/robots.txt b/Website/robots.txt index e687097e20..737f7ca3db 100644 --- a/Website/robots.txt +++ b/Website/robots.txt @@ -1,7 +1,7 @@ User-agent: * # -# Composite C1 will generate a SEO sitemap for /sitemap.xml requests +# Orckestra CMS will generate a SEO sitemap for /sitemap.xml requests # Make the Sitemap URL below absolute (add http://[your hostname]) for this to be correct: # Sitemap: /sitemap.xml From 22ae9babc8df245145e043c5bd6b2831fef65882 Mon Sep 17 00:00:00 2001 From: Marcus Wendt Date: Mon, 19 Sep 2016 14:38:32 +0200 Subject: [PATCH 39/95] Misplaced Always settings in web project - making a number of asmx, ascx and similar files show up below ~/bin after build - removed. --- Website/WebSite.csproj | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Website/WebSite.csproj b/Website/WebSite.csproj index a424a5a963..c0177db0e2 100644 --- a/Website/WebSite.csproj +++ b/Website/WebSite.csproj @@ -259,7 +259,7 @@ ASPXCodeBehind - Always + ASPXCodeBehind @@ -1812,10 +1812,10 @@ Designer - Always + - Always + @@ -2487,52 +2487,52 @@ - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + - Always + From aaed3d651c22f52aaff8b5dac77fc52ee7e09a32 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 19 Sep 2016 15:43:44 +0200 Subject: [PATCH 40/95] nightwatch test fix --- .../test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js index 576bfa53f3..50b05dab36 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js @@ -18,11 +18,11 @@ module.exports = { .clickLabel("Add New") .clickSave() .closeDocumentTab("New Page Metatype") + .assertTreeNodeHasChild("Page Metatypes","newNamespace.myTypeName") .selectPerspective("Content") .openTreeNode("Venus Starter Site") .selectTreeNodeAction("Getting Started","Add Metadata Field") - .selectDialog("Add Metadata Field") .clickDialogButton("Next") .clickDialogButton("Next") .setFieldValue("NewField", "newTextValue") From d5627326ad08fd576333cefdefa53f5f7e86ccb4 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 19 Sep 2016 17:28:32 +0200 Subject: [PATCH 41/95] assert undo changes in edit tests --- Website/test/e2e/suite/400_content/multiEditor.js | 2 ++ Website/test/e2e/suite/400_content/singleEditor.js | 1 + 2 files changed, 3 insertions(+) diff --git a/Website/test/e2e/suite/400_content/multiEditor.js b/Website/test/e2e/suite/400_content/multiEditor.js index d9b529f253..9776d2e79d 100644 --- a/Website/test/e2e/suite/400_content/multiEditor.js +++ b/Website/test/e2e/suite/400_content/multiEditor.js @@ -30,6 +30,8 @@ module.exports = { .selectPerspective("Content") .selectTreeNodeAction("Venus Starter Site","Undo Changes") .selectTreeNodeAction("Venus Starter Site","Publish") + .assertBrowserContains('div.jumbotron-content > h1 > em', 'Venus') + .assertBrowserContainsAttribute('div.jumbotron', 'style', '5.jpg') }, afterEach: function (browser, done) { done(); diff --git a/Website/test/e2e/suite/400_content/singleEditor.js b/Website/test/e2e/suite/400_content/singleEditor.js index f56249e8a0..743f4d8d34 100644 --- a/Website/test/e2e/suite/400_content/singleEditor.js +++ b/Website/test/e2e/suite/400_content/singleEditor.js @@ -21,6 +21,7 @@ module.exports = { .selectPerspective("Content") .selectTreeNodeAction("Getting Started","Undo Changes") .selectTreeNodeAction("Getting Started","Publish") + .assertBrowserContains('div.content-column > h1', 'Getting Started') }, afterEach: function (browser, done) { done(); From c82adde0976ca9f5b1c70cfaaae21df57d1fef48 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Mon, 19 Sep 2016 17:33:28 +0200 Subject: [PATCH 42/95] Fix #228 Saving a page does not update console browser if the page was in "draft" state before that --- .../PageElementProvider/EditPageWorkflow.cs | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs index 3f274b0821..f9a21654de 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs @@ -310,8 +310,6 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) || selectedPage.MenuTitle != originalPage.MenuTitle || selectedPage.Title != originalPage.Title; - var treeviewRequiresRefreshing = false; - var dataToAdd = new Dictionary(); var dataToUpdate = new Dictionary(); @@ -339,12 +337,7 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) } } - bool newDataAdded = PageServices.AddPageTypePageFoldersAndApplications(selectedPage); - - if (newDataAdded) - { - treeviewRequiresRefreshing = true; - } + PageServices.AddPageTypePageFoldersAndApplications(selectedPage); } @@ -361,10 +354,6 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) DataFacade.Update(data); } - treeviewRequiresRefreshing |= (originalPage.Title != selectedPage.Title) || - (originalPage.Description != selectedPage.Description) || - (originalPage.PublicationStatus != selectedPage.PublicationStatus); - // NOTE: updating originalPage object, in order to make XML & SQL provider work in the same way originalPage.TemplateId = selectedPage.TemplateId; originalPage.PageTypeId = selectedPage.PageTypeId; @@ -418,13 +407,10 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) var serviceContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); ActionExecutorFacade.Execute(EntityToken, actionToken, serviceContainer); - - treeviewRequiresRefreshing = false; } - - if (treeviewRequiresRefreshing) + else { - updateTreeRefresher.PostRefreshMesseges(selectedPage.GetDataEntityToken()); + updateTreeRefresher.PostRefreshMessages(selectedPage.GetDataEntityToken()); } UpdateBinding("OldPublicationStatus", selectedPage.PublicationStatus); @@ -547,6 +533,7 @@ private void editPreviewCodeActivity_ExecuteCode(object sender, EventArgs e) } catch (Exception ex) { + // TODO: add html encoding for the exception text Control errOutput = new LiteralControl("
" + ex + "
"); webRenderService.SetNewPageOutput(errOutput); } From d55fd59999407ec0f7a70d48e99ac0eeb1f20768 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Tue, 20 Sep 2016 10:13:10 +0200 Subject: [PATCH 43/95] fixing timeouts according to trunk build speed --- Website/test/e2e/pageObjects/appWindow.js | 4 ++-- Website/test/e2e/pageObjects/content.js | 22 ++++++++++----------- Website/test/e2e/pageObjects/login.js | 4 ++-- Website/test/e2e/pageObjects/startScreen.js | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Website/test/e2e/pageObjects/appWindow.js b/Website/test/e2e/pageObjects/appWindow.js index 4cdc822931..f38383c17b 100644 --- a/Website/test/e2e/pageObjects/appWindow.js +++ b/Website/test/e2e/pageObjects/appWindow.js @@ -13,13 +13,13 @@ module.exports = { this.api.page.startScreen().close(); this .topFrame() - .waitForElementPresent('@appWindow', 1000) + .waitForElementPresent('@appWindow', 10000) return this; }, enter: function () { this .topFrame() - .waitForElementPresent('@appFrame', 1000) + .waitForElementPresent('@appFrame', 10000) .enterFrame('@appFrame'); return this; } diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index 73687b150b..f55464aa2f 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -23,7 +23,7 @@ module.exports = { } this.api.page.appWindow() .enter() - .waitForElementNotPresent('dialogcover[display="block"]', 1000) + .waitForElementNotPresent('dialogcover[display="block"]', 10000) .assert.elementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]') .api.pause(200) .click('#explorer explorertoolbarbutton[label="'+perspective+'"]') @@ -41,15 +41,15 @@ module.exports = { this.api.page.appWindow().prepare(); this .enter(perspective) - .waitForElementVisible('@browserFrame', 2000) - .waitForFrameLoad('@browserFrame', 1000); + .waitForElementVisible('@browserFrame', 10000) + .waitForFrameLoad('@browserFrame', 10000); return this; }, enterTabFrame: function (index) { this .enter() - .waitForElementPresent('view:nth-of-type(' + index + ') window', 1000) - .waitForFrameLoad('view:nth-of-type(' + index + ') window iframe', 1000) + .waitForElementPresent('view:nth-of-type(' + index + ') window', 10000) + .waitForFrameLoad('view:nth-of-type(' + index + ') window iframe', 10000) .enterFrame('view:nth-of-type(' + index + ') window iframe') return this; }, @@ -57,8 +57,8 @@ module.exports = { this .enter() .enterFrame('@browserFrame') - .waitForElementVisible('#browsertabbox iframe', 1000) - .waitForFrameLoad('#browsertabbox iframe', 1000) + .waitForElementVisible('#browsertabbox iframe', 10000) + .waitForFrameLoad('#browsertabbox iframe', 10000) .enterFrame('#browsertabbox iframe') .assert.containsText(selector, value); return this; @@ -67,8 +67,8 @@ module.exports = { this .enter() .enterFrame('@browserFrame') - .waitForElementVisible('#browsertabbox iframe', 1000) - .waitForFrameLoad('#browsertabbox iframe', 1000) + .waitForElementVisible('#browsertabbox iframe', 10000) + .waitForFrameLoad('#browsertabbox iframe', 10000) .enterFrame('#browsertabbox iframe') .useXpath() .assert.elementPresent(selector); @@ -78,8 +78,8 @@ module.exports = { this .enter() .enterFrame('@browserFrame') - .waitForElementVisible('#browsertabbox iframe', 1000) - .waitForFrameLoad('#browsertabbox iframe', 1000) + .waitForElementVisible('#browsertabbox iframe', 10000) + .waitForFrameLoad('#browsertabbox iframe', 10000) .enterFrame('#browsertabbox iframe') .assert.attributeContains(selector,attribiute, value) return this; diff --git a/Website/test/e2e/pageObjects/login.js b/Website/test/e2e/pageObjects/login.js index 3a89421312..97803a0d6d 100644 --- a/Website/test/e2e/pageObjects/login.js +++ b/Website/test/e2e/pageObjects/login.js @@ -10,7 +10,7 @@ module.exports = { commands: [ { isShown: function () { - this.waitForElementVisible('@usernameField', 2500); + this.waitForElementVisible('@usernameField', 10000); return this; }, setUsername: function (username) { @@ -31,7 +31,7 @@ module.exports = { .setUsername(username || 'admin') .setPassword(password || '123456') .click('@submitButton') - .waitForElementNotVisible('@usernameField', 1000); + .waitForElementNotVisible('@usernameField', 10000); } } ] diff --git a/Website/test/e2e/pageObjects/startScreen.js b/Website/test/e2e/pageObjects/startScreen.js index e3b16a9ef4..9ab89a0a3a 100644 --- a/Website/test/e2e/pageObjects/startScreen.js +++ b/Website/test/e2e/pageObjects/startScreen.js @@ -12,7 +12,7 @@ module.exports = { }, enter: function () { this.api.page.appWindow().enter(); // Start page shows inside appwindow. - this.waitForElementPresent('@startFrame', 3000); + this.waitForElementPresent('@startFrame', 10000); this.api.pause(1000); this.enterFrame('@startFrame'); // Enter the frame containing it return this; From cb96038a706bb7baae2aca82681d073336f4311d Mon Sep 17 00:00:00 2001 From: Taras Nakonechnyi Date: Tue, 20 Sep 2016 15:18:54 +0300 Subject: [PATCH 44/95] Add data-qa attribute to SystemPage after it initialized --- .../ui/bindings/system/SystemPageBinding.js | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/Website/Composite/scripts/source/top/ui/bindings/system/SystemPageBinding.js b/Website/Composite/scripts/source/top/ui/bindings/system/SystemPageBinding.js index 6c6cdb484c..aa605579c0 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/system/SystemPageBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/system/SystemPageBinding.js @@ -12,13 +12,13 @@ function SystemPageBinding () { * @type {SystemLogger} */ this.logger = SystemLogger.getLogger ( "SystemPageBinding" ); - + /** * Supplied as page argument. * @type {SystemNode} */ this.node = null; - + /** * @type {SystemTree} */ @@ -29,7 +29,7 @@ function SystemPageBinding () { * Identifies binding. */ SystemPageBinding.prototype.toString = function () { - + return "[SystemPageBinding]"; } @@ -37,7 +37,7 @@ SystemPageBinding.prototype.toString = function () { * @overloads {PageBinding#onBindingRegister} */ SystemPageBinding.prototype.onBindingRegister = function () { - + SystemPageBinding.superclass.onBindingRegister.call ( this ); this.subscribe ( BroadcastMessages.SYSTEMTREEBINDING_REFRESH ); this.addActionListener ( ButtonBinding.ACTION_COMMAND ); @@ -48,7 +48,7 @@ SystemPageBinding.prototype.onBindingRegister = function () { * @param {SystemNode} systemNode */ SystemPageBinding.prototype.setPageArgument = function ( systemNode ) { - + this.node = systemNode; SystemPageBinding.superclass.setPageArgument.call ( this, systemNode ); } @@ -68,7 +68,7 @@ SystemPageBinding.prototype.onBeforePageInitialize = function () { } else { throw "SystemPageBinding requires a SystemNode"; } - + SystemPageBinding.superclass.onBeforePageInitialize.call ( this ); } @@ -80,11 +80,11 @@ SystemPageBinding.prototype._buildTree = function () { var children = this.node.getChildren (); if ( children.hasEntries ()) { while ( children.hasNext ()) { - var node = SystemTreeNodeBinding.newInstance ( - children.getNext (), - this.bindingDocument + var node = SystemTreeNodeBinding.newInstance ( + children.getNext (), + this.bindingDocument ) - this._tree.add ( node ); + this._tree.add ( node ); node.attach (); } } @@ -94,11 +94,11 @@ SystemPageBinding.prototype._buildTree = function () { * Refresh tree. */ SystemPageBinding.prototype._refreshTree = function () { - - /* - * Preopen non-container root nodes. That aint right, - * but they will get replaced by fresh nodes anyway. - * This will let the user see a newly added treenode + + /* + * Preopen non-container root nodes. That aint right, + * but they will get replaced by fresh nodes anyway. + * This will let the user see a newly added treenode * without opening container, at least at root level. */ var roots = this._tree._treeBodyBinding.getChildBindingsByLocalName ( "treenode" ); @@ -107,37 +107,37 @@ SystemPageBinding.prototype._refreshTree = function () { root.isOpen = true; } }); - - + + // Collect open treenodes. var crawler = new TreeCrawler (); var opens = new List (); crawler.mode = TreeCrawler.MODE_GETOPEN; crawler.crawl ( this.bindingElement, opens ); crawler.dispose (); - + // Extract open SystemNodes. var list = new List ([ this.node ]); opens.each ( function ( treenode ) { list.add ( treenode.node ); }); - + // Empty tree and build new. this._tree.empty (); var branch = this.node.getDescendantBranch ( list ); if ( branch.hasEntries ()) { - + var self = this; var map = new Map (); - + /* - * Note that this is basically a copy-paste + * Note that this is basically a copy-paste * of some stoff going on in SystemTreeNode. */ branch.each ( function ( key, nodes ) { nodes.each ( function ( node ) { - + var treenode = SystemTreeNodeBinding.newInstance ( node, self.bindingDocument ); map.set ( node.getHandle (), treenode ); if ( map.has ( key )) { @@ -149,7 +149,7 @@ SystemPageBinding.prototype._refreshTree = function () { } }); }); - + this._tree.attachRecursive (); } } @@ -158,9 +158,15 @@ SystemPageBinding.prototype._refreshTree = function () { * Executed when the page is shown. Select first treenode. */ SystemPageBinding.prototype.onAfterPageInitialize = function () { - + SystemPageBinding.superclass.onAfterPageInitialize.call ( this ); - this._tree.selectDefault (); + this._tree.selectDefault(); + + if (Application.isTestEnvironment) { + try { + this.setProperty("data-qa", this.node.getTag()); + } catch (exception) { } + } } /** @@ -169,12 +175,12 @@ SystemPageBinding.prototype.onAfterPageInitialize = function () { * @param {Action} action */ SystemPageBinding.prototype.handleAction = function ( action ) { - + SystemPageBinding.superclass.handleAction.call ( this, action ) - + switch ( action.type ) { case ButtonBinding.ACTION_COMMAND : - var button = action.target; + var button = action.target; switch ( button.getID ()) { case "locktreebutton" : this._tree.setLockToEditor ( button.isChecked ); @@ -193,16 +199,16 @@ SystemPageBinding.prototype.handleAction = function ( action ) { * @param {object} arg */ SystemPageBinding.prototype.handleBroadcast = function ( broadcast, arg ) { - + SystemPageBinding.superclass.handleBroadcast.call ( this, broadcast, arg ); - + /* - * This is basically a copy of the procedure instiaged + * This is basically a copy of the procedure instiaged * at SystemTreeNodeBinding method "refresh". */ switch ( broadcast ) { case BroadcastMessages.SYSTEMTREEBINDING_REFRESH : - + var token = arg; if ( this.node && this.node.getEntityToken () == token ) { try { From 53efc34014f303578e97a5464edb8e29fca9e531 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Tue, 20 Sep 2016 18:01:28 +0200 Subject: [PATCH 45/95] add connection string to sql package installation, centralize timeout values, --- .../test/e2e/ApiLang/Notepad++/Nightwatch.UDL | 2 +- .../test/e2e/ApiLang/Notepad++/nightwatch.xml | 11 ++++++++ Website/test/e2e/commands/assertFieldValue.js | 4 +-- .../test/e2e/commands/clickDataBySibilings.js | 4 +-- .../test/e2e/commands/clickDialogButton.js | 2 +- Website/test/e2e/commands/clickInFrame.js | 2 +- Website/test/e2e/commands/clickLabel.js | 6 ++--- Website/test/e2e/commands/clickSave.js | 2 +- Website/test/e2e/commands/clickText.js | 4 +-- Website/test/e2e/commands/enterFrame.js | 1 - Website/test/e2e/commands/selectContentTab.js | 4 +-- Website/test/e2e/commands/selectDialog.js | 4 +-- .../test/e2e/commands/selectDocumentTab.js | 4 +-- Website/test/e2e/commands/setFieldValue.js | 9 +++---- .../e2e/commands/setFieldValueInFieldGroup.js | 8 +++--- Website/test/e2e/globals.js | 5 ++++ Website/test/e2e/pageObjects/appWindow.js | 4 +-- Website/test/e2e/pageObjects/content.js | 26 +++++++++---------- Website/test/e2e/pageObjects/editor.js | 10 +++---- Website/test/e2e/pageObjects/login.js | 4 +-- Website/test/e2e/pageObjects/startScreen.js | 3 +-- Website/test/e2e/pageObjects/systemView.js | 19 ++++++++++---- .../e2e/suite/000_setup/InstalSQLPackage.js | 14 ++++++++-- 23 files changed, 92 insertions(+), 60 deletions(-) diff --git a/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL b/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL index 79efb7682d..668c5762cf 100644 --- a/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL +++ b/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL @@ -24,7 +24,7 @@ - assertBrowserContainsAttribute assertBrowserContains assertFieldValue assertTreeNodeHasChild assertTreeNodeIsEmpty assertTreeNodeIsNotEmpty clickDataBySibilings clickDialogButton clickInFrame clickLabel clickSave replaceTextInCodeMirror selectEditOnContent clickText closeDocumentTab changeElementContent doubleClickSelector enterFrame leaveFrame openTreeNode replaceContent rightClickSelector selectActionFromToolbar selectContentTab selectDialog selectDocumentTab selectFrame selectFrameWithXpath selectPerspective selectTreeNodeAction setFieldValueInFieldGroup setFieldValue switchContentTab topFrame waitForFrameLoad acceptChanges acceptFunctionEdit + assertBrowserContainsAttribute assertBrowserContains assertFieldValue assertTreeNodeHasChild assertTreeNodeIsEmpty assertTreeNodeIsNotEmpty clickDataBySibilings clickDialogButton clickInFrame clickLabel clickSave replaceTextInCodeMirror selectEditOnContent clickText closeDocumentTab changeElementContent doubleClickSelector enterFrame leaveFrame openTreeNode replaceContent rightClickSelector selectActionFromToolbar selectContentTab selectDialog selectDocumentTab selectFrame selectFrameWithXpath selectPerspective selectTreeNodeAction setFieldValueInFieldGroup setFieldValue switchContentTab topFrame waitForFrameLoad acceptChanges acceptFunctionEdit assertTreeNodeHasNoChild submitFormData browser editor2 editor beforeEach afterEach done diff --git a/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml b/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml index 9d8f1e2797..b94e82f4bf 100644 --- a/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml +++ b/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml @@ -49,6 +49,12 @@ + + + + + + @@ -195,6 +201,11 @@ + + + + + diff --git a/Website/test/e2e/commands/assertFieldValue.js b/Website/test/e2e/commands/assertFieldValue.js index d3f63af510..0e21dde03a 100644 --- a/Website/test/e2e/commands/assertFieldValue.js +++ b/Website/test/e2e/commands/assertFieldValue.js @@ -9,13 +9,13 @@ AssertFieldValue.prototype.command = function (dialogLabel,fieldLabel,vlaueToAss inputType = "input"; } if (dialogLabel == null) { - this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]'); } else { this.client.api.selectFrameWithXpath('//*[local-name() = "fieldgroup"][@label="' + dialogLabel + '"]'); } this.client.api .useXpath() - .getValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]',function(result) { + .getValue('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]',function(result) { this.assert.equal(typeof result, "object"); this.assert.equal(result.status, 0); this.assert.equal(result.value, vlaueToAssert); diff --git a/Website/test/e2e/commands/clickDataBySibilings.js b/Website/test/e2e/commands/clickDataBySibilings.js index 7282a123b6..34bd9ad14c 100644 --- a/Website/test/e2e/commands/clickDataBySibilings.js +++ b/Website/test/e2e/commands/clickDataBySibilings.js @@ -5,11 +5,11 @@ function ClickDataBySibiling() { } ClickDataBySibiling.prototype.command = function (vlaue) { - this.client.api.selectFrameWithXpath('//*[local-name()="fielddesc"][text()="'+vlaue+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name()="fielddesc"][normalize-space(text())="'+vlaue+'"]'); this.client.api .useXpath() - .click('//*[local-name()="fielddesc"][text()="'+vlaue+'"]/..//*[local-name()="fielddata"]').useCss() + .click('//*[local-name()="fielddesc"][normalize-space(text())="'+vlaue+'"]/..//*[local-name()="fielddata"]').useCss() return this.client.api; }; diff --git a/Website/test/e2e/commands/clickDialogButton.js b/Website/test/e2e/commands/clickDialogButton.js index 344f826ce4..cf2e936e7f 100644 --- a/Website/test/e2e/commands/clickDialogButton.js +++ b/Website/test/e2e/commands/clickDialogButton.js @@ -10,7 +10,7 @@ util.inherits(ClickOnDialogButton, events.EventEmitter); ClickOnDialogButton.prototype.command = function (button) { this.client.api .selectFrame('#dialogbuttonstoolbar') - .waitForElementVisible('clickbutton[label="' + button + '"]', 1000) + .waitForElementVisible('clickbutton[label="' + button + '"]', this.api.globals.timeouts.basic) .click('clickbutton[label="'+button+'"]', () => this.emit('complete')) return this.client.api; }; diff --git a/Website/test/e2e/commands/clickInFrame.js b/Website/test/e2e/commands/clickInFrame.js index 6dc249f232..59b8cdf4aa 100644 --- a/Website/test/e2e/commands/clickInFrame.js +++ b/Website/test/e2e/commands/clickInFrame.js @@ -7,7 +7,7 @@ exports.command = function (frameSelector, buttonSelector, waitTime) { } this.selectFrame(frameSelector); - this.waitForElementVisible(buttonSelector, waitTime || 1000); + this.waitForElementVisible(buttonSelector, waitTime || this.api.globals.timeouts.basic); this.click(buttonSelector); if (waitTime) { this.pause(waitTime); diff --git a/Website/test/e2e/commands/clickLabel.js b/Website/test/e2e/commands/clickLabel.js index 64f517cd00..f09b37ba70 100644 --- a/Website/test/e2e/commands/clickLabel.js +++ b/Website/test/e2e/commands/clickLabel.js @@ -6,17 +6,17 @@ function ClickLabel() { ClickLabel.prototype.command = function (label,parentLabel) { var selector; - if(parentLabel===null){ + if(parentLabel==null){ selector ='//*[@label="'+label+'"]'; } else{ selector= '//*[@label="'+parentLabel+'"]//*[@label="'+label+'"]' } - this.client.api.selectFrameWithXpath('//*[@label="'+label+'"]'); + this.client.api.selectFrameWithXpath(selector); this.client.api .useXpath() - .moveToElement('//*[@label="'+label+'"]',null,null) + .moveToElement(selector,null,null) .mouseButtonClick('left').useCss() return this.client.api; diff --git a/Website/test/e2e/commands/clickSave.js b/Website/test/e2e/commands/clickSave.js index 01e2f3c7c1..bf125e7e52 100644 --- a/Website/test/e2e/commands/clickSave.js +++ b/Website/test/e2e/commands/clickSave.js @@ -9,7 +9,7 @@ ClickSave.prototype.command = function () { .selectFrame('#savebutton'); this.client.api.expect.element('#savebutton').to.not.have.attribute('isdisabled'); this.client.api.click('#savebutton > labelbox'); - this.client.api.waitForElementVisible('#savebutton[isdisabled="true"]',60000); + this.client.api.waitForElementVisible('#savebutton[isdisabled="true"]',this.api.globals.timeouts.save); return this.client.api; }; diff --git a/Website/test/e2e/commands/clickText.js b/Website/test/e2e/commands/clickText.js index a42fdc52da..da9ca36e91 100644 --- a/Website/test/e2e/commands/clickText.js +++ b/Website/test/e2e/commands/clickText.js @@ -5,11 +5,11 @@ function ClickText() { } ClickText.prototype.command = function (vlaue) { - this.client.api.selectFrameWithXpath('//*[text()="'+vlaue+'"]'); + this.client.api.selectFrameWithXpath('//*[normalize-space(text())="'+vlaue+'"]'); this.client.api .useXpath() - .click('//*[text()="'+vlaue+'"]').useCss() + .click('//*[normalize-space(text())="'+vlaue+'"]').useCss() return this.client.api; }; diff --git a/Website/test/e2e/commands/enterFrame.js b/Website/test/e2e/commands/enterFrame.js index ad19df1e18..cef6fe3a5c 100644 --- a/Website/test/e2e/commands/enterFrame.js +++ b/Website/test/e2e/commands/enterFrame.js @@ -17,7 +17,6 @@ EnterFrame.prototype.command = function(selector) { this.client.api.frame( result.value, () => { - // this.client.assertion(true, null, null, 'Entered frame <' + selector + '>', this.abortOnFailure); this.emit('complete'); } ); diff --git a/Website/test/e2e/commands/selectContentTab.js b/Website/test/e2e/commands/selectContentTab.js index 2e10ac2bed..bde27bea48 100644 --- a/Website/test/e2e/commands/selectContentTab.js +++ b/Website/test/e2e/commands/selectContentTab.js @@ -5,10 +5,10 @@ function SelectContentTab() { } SelectContentTab.prototype.command = function (tabName) { - this.client.api.selectFrameWithXpath('//*[local-name() = "tabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name() = "tabs"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]'); this.client.api .useXpath() - .click('//*[local-name() = "tabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]').useCss() + .click('//*[local-name() = "tabs"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]').useCss() return this.client.api; }; diff --git a/Website/test/e2e/commands/selectDialog.js b/Website/test/e2e/commands/selectDialog.js index ebe89941ab..d9f4b96c6d 100644 --- a/Website/test/e2e/commands/selectDialog.js +++ b/Website/test/e2e/commands/selectDialog.js @@ -5,10 +5,10 @@ function SelectDialog() { } SelectDialog.prototype.command = function (tabName) { - this.client.api.selectFrameWithXpath('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]'); this.client.api .useXpath() - .click('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]').useCss() + .click('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]').useCss() return this.client.api; }; diff --git a/Website/test/e2e/commands/selectDocumentTab.js b/Website/test/e2e/commands/selectDocumentTab.js index 72aaa752bb..145bdb46c5 100644 --- a/Website/test/e2e/commands/selectDocumentTab.js +++ b/Website/test/e2e/commands/selectDocumentTab.js @@ -5,10 +5,10 @@ function SelectDocumentTab() { } SelectDocumentTab.prototype.command = function (tabName) { - this.client.api.selectFrameWithXpath('//*[local-name() = "docktabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name() = "docktabs"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]'); this.client.api .useXpath() - .click('//*[local-name() = "docktabs"]/*//*[local-name() = "labeltext"][text()="'+tabName+'"]').useCss(); + .click('//*[local-name() = "docktabs"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]').useCss(); return this.client.api; }; diff --git a/Website/test/e2e/commands/setFieldValue.js b/Website/test/e2e/commands/setFieldValue.js index dd52c89baa..f38065a710 100644 --- a/Website/test/e2e/commands/setFieldValue.js +++ b/Website/test/e2e/commands/setFieldValue.js @@ -8,14 +8,13 @@ SetValueByLabel.prototype.command = function (fieldLabel,value,inputType) { if(inputType == null){ inputType = "input"; } - - this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]'); this.client.api .useXpath() - .click('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') - .clearValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') - .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', value) + .click('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .clearValue('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .setValue('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', value) .assertFieldValue(null,fieldLabel,value,inputType) return this.client.api; }; diff --git a/Website/test/e2e/commands/setFieldValueInFieldGroup.js b/Website/test/e2e/commands/setFieldValueInFieldGroup.js index 710866b91c..477bcef282 100644 --- a/Website/test/e2e/commands/setFieldValueInFieldGroup.js +++ b/Website/test/e2e/commands/setFieldValueInFieldGroup.js @@ -9,15 +9,15 @@ SetValueByLabelFieldGroup.prototype.command = function (dialogLabel,fieldLabel,v inputType = "input"; } if (dialogLabel == null) { - this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]'); + this.client.api.selectFrameWithXpath('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]'); } else { this.client.api.selectFrameWithXpath('//*[local-name() = "fieldgroup"][@label="' + dialogLabel + '"]'); } this.client.api .useXpath() - .click('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') - .clearValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') - .setValue('//*[local-name() = "fielddesc"][text()="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', value) + .click('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .clearValue('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]') + .setValue('//*[local-name() = "fielddesc"][normalize-space(text())="'+fieldLabel+'"]/parent::*//*[local-name() = "'+inputType+'"]', value) .assertFieldValue(dialogLabel,fieldLabel,value,inputType) return this.client.api; }; diff --git a/Website/test/e2e/globals.js b/Website/test/e2e/globals.js index 2ace14c455..d19a23a07d 100644 --- a/Website/test/e2e/globals.js +++ b/Website/test/e2e/globals.js @@ -1,4 +1,9 @@ +var timeouts = { + basic: 10000, + save: 60000, + }; module.exports = { + timeouts : timeouts, beforeEach: function (browser, done) { browser.resizeWindow(1400, 1000, done); }, diff --git a/Website/test/e2e/pageObjects/appWindow.js b/Website/test/e2e/pageObjects/appWindow.js index f38383c17b..05f5862b04 100644 --- a/Website/test/e2e/pageObjects/appWindow.js +++ b/Website/test/e2e/pageObjects/appWindow.js @@ -13,13 +13,13 @@ module.exports = { this.api.page.startScreen().close(); this .topFrame() - .waitForElementPresent('@appWindow', 10000) + .waitForElementPresent('@appWindow', this.api.globals.timeouts.basic) return this; }, enter: function () { this .topFrame() - .waitForElementPresent('@appFrame', 10000) + .waitForElementPresent('@appFrame', this.api.globals.timeouts.basic) .enterFrame('@appFrame'); return this; } diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index f55464aa2f..1fe85df893 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -23,11 +23,11 @@ module.exports = { } this.api.page.appWindow() .enter() - .waitForElementNotPresent('dialogcover[display="block"]', 10000) - .assert.elementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]') + .waitForElementNotPresent('dialogcover[style*="block"]', this.api.globals.timeouts.basic) + .waitForElementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]', this.api.globals.timeouts.basic) .api.pause(200) .click('#explorer explorertoolbarbutton[label="'+perspective+'"]') - .waitForFrameLoad('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe', 10000) + .waitForFrameLoad('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe', this.api.globals.timeouts.basic) .enterFrame('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe'); return this; }, @@ -41,15 +41,15 @@ module.exports = { this.api.page.appWindow().prepare(); this .enter(perspective) - .waitForElementVisible('@browserFrame', 10000) - .waitForFrameLoad('@browserFrame', 10000); + .waitForElementVisible('@browserFrame', this.api.globals.timeouts.basic) + .waitForFrameLoad('@browserFrame', this.api.globals.timeouts.basic); return this; }, enterTabFrame: function (index) { this .enter() - .waitForElementPresent('view:nth-of-type(' + index + ') window', 10000) - .waitForFrameLoad('view:nth-of-type(' + index + ') window iframe', 10000) + .waitForElementPresent('view:nth-of-type(' + index + ') window', this.api.globals.timeouts.basic) + .waitForFrameLoad('view:nth-of-type(' + index + ') window iframe', this.api.globals.timeouts.basic) .enterFrame('view:nth-of-type(' + index + ') window iframe') return this; }, @@ -57,8 +57,8 @@ module.exports = { this .enter() .enterFrame('@browserFrame') - .waitForElementVisible('#browsertabbox iframe', 10000) - .waitForFrameLoad('#browsertabbox iframe', 10000) + .waitForElementVisible('#browsertabbox iframe', this.api.globals.timeouts.basic) + .waitForFrameLoad('#browsertabbox iframe', this.api.globals.timeouts.basic) .enterFrame('#browsertabbox iframe') .assert.containsText(selector, value); return this; @@ -67,8 +67,8 @@ module.exports = { this .enter() .enterFrame('@browserFrame') - .waitForElementVisible('#browsertabbox iframe', 10000) - .waitForFrameLoad('#browsertabbox iframe', 10000) + .waitForElementVisible('#browsertabbox iframe', this.api.globals.timeouts.basic) + .waitForFrameLoad('#browsertabbox iframe', this.api.globals.timeouts.basic) .enterFrame('#browsertabbox iframe') .useXpath() .assert.elementPresent(selector); @@ -78,8 +78,8 @@ module.exports = { this .enter() .enterFrame('@browserFrame') - .waitForElementVisible('#browsertabbox iframe', 10000) - .waitForFrameLoad('#browsertabbox iframe', 10000) + .waitForElementVisible('#browsertabbox iframe', this.api.globals.timeouts.basic) + .waitForFrameLoad('#browsertabbox iframe', this.api.globals.timeouts.basic) .enterFrame('#browsertabbox iframe') .assert.attributeContains(selector,attribiute, value) return this; diff --git a/Website/test/e2e/pageObjects/editor.js b/Website/test/e2e/pageObjects/editor.js index 6332330422..1a4fa9473f 100644 --- a/Website/test/e2e/pageObjects/editor.js +++ b/Website/test/e2e/pageObjects/editor.js @@ -33,11 +33,11 @@ module.exports = { .enter() .assert.attributeEquals('body', 'contenteditable', 'true') .client.api.useXpath() - .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',60000) + .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',this.api.globals.timeouts.basic) .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) .mouseButtonClick('right') .selectFrameWithXpath('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"]') - .waitForElementVisible('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]',60000) + .waitForElementVisible('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]',this.api.globals.timeouts.basic) .click('//*[local-name() = "menuitem"]//*[local-name() = "labelbox"][@label="'+action+'"]').useCss() return this; }, @@ -46,14 +46,14 @@ module.exports = { .enter() .assert.attributeEquals('body', 'contenteditable', 'true') .client.api.useXpath() - .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',60000) + .waitForElementVisible('//*[@id="tinymce"]/*['+number+']',this.api.globals.timeouts.basic) .moveToElement('//*[@id="tinymce"]/*['+number+']',null,null) .click('//*[@id="tinymce"]/*['+number+']') .selectFrame('toolbar[binding="VisualEditorToolBarBinding"]') - .waitForElementPresent('//*[local-name()="labeltext"][text()="Function Properties…"]',60000) + .waitForElementPresent('//*[local-name()="labeltext"][text()="Function Properties…"]',this.api.globals.timeouts.basic) .clickText("Function Properties…") this.client.api.page.appWindow().enter() - .waitForElementPresent('iframe[src="/Composite/content/dialogs/postback/postbackdialog.aspx"]',60000) + .waitForElementPresent('iframe[src="/Composite/content/dialogs/postback/postbackdialog.aspx"]',this.api.globals.timeouts.basic) return this; }, acceptChanges: function (){ diff --git a/Website/test/e2e/pageObjects/login.js b/Website/test/e2e/pageObjects/login.js index 97803a0d6d..a88ce37dc7 100644 --- a/Website/test/e2e/pageObjects/login.js +++ b/Website/test/e2e/pageObjects/login.js @@ -10,7 +10,7 @@ module.exports = { commands: [ { isShown: function () { - this.waitForElementVisible('@usernameField', 10000); + this.waitForElementVisible('@usernameField', this.api.globals.timeouts.basic); return this; }, setUsername: function (username) { @@ -31,7 +31,7 @@ module.exports = { .setUsername(username || 'admin') .setPassword(password || '123456') .click('@submitButton') - .waitForElementNotVisible('@usernameField', 10000); + .waitForElementNotVisible('@usernameField', this.api.globals.timeouts.basic); } } ] diff --git a/Website/test/e2e/pageObjects/startScreen.js b/Website/test/e2e/pageObjects/startScreen.js index 9ab89a0a3a..2784e99943 100644 --- a/Website/test/e2e/pageObjects/startScreen.js +++ b/Website/test/e2e/pageObjects/startScreen.js @@ -12,8 +12,7 @@ module.exports = { }, enter: function () { this.api.page.appWindow().enter(); // Start page shows inside appwindow. - this.waitForElementPresent('@startFrame', 10000); - this.api.pause(1000); + this.waitForElementPresent('@startFrame', this.api.globals.timeouts.basic); this.enterFrame('@startFrame'); // Enter the frame containing it return this; }, diff --git a/Website/test/e2e/pageObjects/systemView.js b/Website/test/e2e/pageObjects/systemView.js index 7a57a4f7e7..6450b83e5a 100644 --- a/Website/test/e2e/pageObjects/systemView.js +++ b/Website/test/e2e/pageObjects/systemView.js @@ -8,7 +8,7 @@ module.exports = { .enter(perspective) .enterFrame('@browserFrame'); this - .waitForFrameLoad('@systemFrame', 10000) + .waitForFrameLoad('@systemFrame', this.api.globals.timeouts.basic) .enterFrame('@systemFrame'); return this; }, @@ -17,7 +17,7 @@ module.exports = { .enterActivePerspective() .enterFrame('@browserFrame'); this - .waitForFrameLoad('@systemFrame', 10000) + .waitForFrameLoad('@systemFrame', this.api.globals.timeouts.basic) .enterFrame('@systemFrame'); return this; }, @@ -27,7 +27,7 @@ module.exports = { selector += 'treenode[label="' + childLabel + '"] > '; } selector += 'labelbox'; - this.api.waitForElementPresent(selector,10000) + this.api.waitForElementPresent(selector,this.api.globals.timeouts.basic) this.doubleClickSelector(selector); this.api.pause(300); return this; @@ -38,7 +38,7 @@ module.exports = { selector += 'treenode[label="' + childLabel + '"] > '; } selector +='labelbox'; - this.api.waitForElementPresent(selector,10000) + this.api.waitForElementPresent(selector,this.api.globals.timeouts.basic) this.click(selector); return this; }, @@ -48,7 +48,7 @@ module.exports = { selector += 'treenode[label="' + childLabel + '"] > '; } selector +='labelbox'; - this.api.waitForElementPresent(selector,10000) + this.api.waitForElementPresent(selector,this.api.globals.timeouts.basic) this.rightClickSelector(selector); return this; }, @@ -61,6 +61,15 @@ module.exports = { .element(selector) .to.be.present; }, + _assertTreeNodeHasNoChild: function (parentLabel, childLabel) { + var selector = 'treenode[label="' + parentLabel + '"] > treenode'; + if (childLabel) { + selector += '[label="' + childLabel + '"]'; + } + this.expect + .element(selector) + .not.to.be.present; + }, _assertTreeNodeIsEmpty: function (parentLabel,childLabel) { var selector = 'treenode[label="' + parentLabel + '"] > treenode'; if (childLabel) { diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js index 247f60ee1d..6eb9a8d98a 100644 --- a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -21,9 +21,19 @@ module.exports = { browser .selectPerspective("System") - .openTreeNode("Installed Packages") - .openTreeNode("Composite.Tools") + .openTreeNode("Packages","Installed Packages") + .openTreeNode("Installed Packages","Composite.Tools") .assertTreeNodeHasChild("Composite.Tools","Composite.Tools.SqlServerDataProvider") + + .selectTreeNodeAction("SqlServer Data Provider","Convert to SQL") + .selectDocumentTab("Convert to SQL") + .setFieldValue("Connection String:",browser.globals.connectionString) + .submitFormData('Next') + .submitFormData('Finish') + + .selectPerspective("System") + .assertTreeNodeHasNoChild("SqlServer Data Provider") + }, afterEach: function (browser, done) { done(); From e63b970078d0c5d700a484ecdf4ea2c3d08e4c64 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 21 Sep 2016 09:57:22 +0200 Subject: [PATCH 46/95] add missing commands --- .../e2e/commands/assertTreeNodeHasNoChild.js | 16 ++++++++++++++++ Website/test/e2e/commands/submitFormData.js | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 Website/test/e2e/commands/assertTreeNodeHasNoChild.js create mode 100644 Website/test/e2e/commands/submitFormData.js diff --git a/Website/test/e2e/commands/assertTreeNodeHasNoChild.js b/Website/test/e2e/commands/assertTreeNodeHasNoChild.js new file mode 100644 index 0000000000..eaa4b36be8 --- /dev/null +++ b/Website/test/e2e/commands/assertTreeNodeHasNoChild.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function AssertTreeNodeHasChild() { + events.EventEmitter.call(this); +} + +AssertTreeNodeHasChild.prototype.command = function (parentLabel, childLabel) { + var content = this.client.api.page.content(); + var systemView = this.client.api.page.systemView(); + systemView + .enterActivePerspective() + ._assertTreeNodeHasNoChild(parentLabel, childLabel); + return this.client.api; +}; + +module.exports = AssertTreeNodeHasChild; diff --git a/Website/test/e2e/commands/submitFormData.js b/Website/test/e2e/commands/submitFormData.js new file mode 100644 index 0000000000..7159fe73c7 --- /dev/null +++ b/Website/test/e2e/commands/submitFormData.js @@ -0,0 +1,16 @@ +var events = require('events'); + +function SubmitForm() { + events.EventEmitter.call(this); +} + +SubmitForm.prototype.command = function (submitValue) { + this.client.api.selectFrameWithXpath('//*[local-name()="input"][@value="'+submitValue+'"]'); + this.client.api + .useXpath() + .click('//*[local-name()="input"][@value="'+submitValue+'"]') + + return this.client.api; +}; + +module.exports = SubmitForm; \ No newline at end of file From f7d50dafd100a69ebae6cbfdde6e738f7a0ab0ff Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 21 Sep 2016 11:42:12 +0200 Subject: [PATCH 47/95] fix content load checking, global timeouts in install test --- Website/test/e2e/globals.js | 3 ++- Website/test/e2e/pageObjects/content.js | 2 +- .../test/e2e/suite/000_setup/installSite.js | 24 +++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Website/test/e2e/globals.js b/Website/test/e2e/globals.js index d19a23a07d..d99ea6ab6f 100644 --- a/Website/test/e2e/globals.js +++ b/Website/test/e2e/globals.js @@ -1,6 +1,7 @@ var timeouts = { basic: 10000, - save: 60000, + save: 120000, + little: 1000, }; module.exports = { timeouts : timeouts, diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index 1fe85df893..4654230f9e 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -23,7 +23,7 @@ module.exports = { } this.api.page.appWindow() .enter() - .waitForElementNotPresent('dialogcover[style*="block"]', this.api.globals.timeouts.basic) + .waitForElementNotPresent('dialogcover[hidden="true"]', this.api.globals.timeouts.basic) .waitForElementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]', this.api.globals.timeouts.basic) .api.pause(200) .click('#explorer explorertoolbarbutton[label="'+perspective+'"]') diff --git a/Website/test/e2e/suite/000_setup/installSite.js b/Website/test/e2e/suite/000_setup/installSite.js index 589fe34033..2905924198 100644 --- a/Website/test/e2e/suite/000_setup/installSite.js +++ b/Website/test/e2e/suite/000_setup/installSite.js @@ -18,20 +18,20 @@ module.exports = { // 1 Launch an uninitialized website. browser .url(browser.launchUrl + '/Composite/top.aspx') - .waitForElementVisible('.welcomepage', 10000); + .waitForElementVisible('.welcomepage', browser.globals.timeouts.basic); }, 'install Venus starter site': function (browser) { browser // The “Welcome” page of the setup wizard appears. - .waitForElementVisible('#intro', 1000) + .waitForElementVisible('#intro', browser.globals.timeouts.little) // All the requirements are met (checked). - .waitForElementVisible('#introtestsuccess', 5000) + .waitForElementVisible('#introtestsuccess', browser.globals.timeouts.basic) // The “Next” button is available and enabled - .waitForElementVisible('#introtestsuccessbutton', 1000) + .waitForElementVisible('#introtestsuccessbutton', browser.globals.timeouts.little) // 2 Click “Next”. The “License” page of the setup wizard appears. .click('#introtestsuccessbutton') // The “Accept” check box is present and unchecked - .waitForElementVisible('#licenseaccept', 1000); + .waitForElementVisible('#licenseaccept', browser.globals.timeouts.little); browser.expect.element('#licenseaccept').to.not.have.attribute('checked'); // The “Next” button is available but disabled browser.expect.element('#setupbutton').to.have.attribute('isdisabled'); @@ -43,7 +43,7 @@ module.exports = { browser .click('#setupbutton') // The “Starter Site” radio button is present and selected - .waitForElementVisible('#setup', 1000); + .waitForElementVisible('#setup', browser.globals.timeouts.little); browser.expect.element('#setup h1').text.to.contain('Setup'); // The “Venus” radio button is present and selected. browser.expect @@ -63,7 +63,7 @@ module.exports = { // 5 Click “Next”. The “Language” page of the setup wizard appears. browser .click('#navsetup clickbutton[label="Next"]') - .waitForElementVisible('#language', 1000); + .waitForElementVisible('#language', browser.globals.timeouts.little); // A language is selected. (It must be based on the user’s locale.) browser.expect.element('#websitelanguage').value.to.equal(expectedLanguage); // The “Next” button is available and enabled @@ -71,7 +71,7 @@ module.exports = { // 6 Click “Next”. The “Create Login” page of the setup wizard appears. browser .click('#navlanguage clickbutton[label="Next"]') - .waitForElementVisible('#login', 1000); + .waitForElementVisible('#login', browser.globals.timeouts.little); // The “Start C1” button is available but disabled. browser.expect .element('#navlogin clickbutton[label="Start C1"]') @@ -121,11 +121,11 @@ module.exports = { // and installed…” appears showing the installation progress and // other screens succeed each other. browser - .waitForElementVisible('#loading', 1000) + .waitForElementVisible('#loading', browser.globals.timeouts.little) // Eventually, the user logs in successfully and the C1 Console appears. - .waitForElementNotPresent('#loading', 60000) - .waitForElementVisible('body', 10000) + .waitForElementNotPresent('#loading', browser.globals.timeouts.save) + .waitForElementVisible('body', browser.globals.timeouts.basic) .page.appWindow() - .waitForFrameLoad('@appFrame', 1000); + .waitForFrameLoad('@appFrame', browser.globals.timeouts.little); } } From 5d0f95582df0e391061681a69e8f2a845dbd6bb7 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 21 Sep 2016 11:48:45 +0200 Subject: [PATCH 48/95] check cleanup phase --- Website/test/e2e/suite/500_duplicate/Duplicate.js | 1 + .../test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js | 1 + Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js | 1 + .../test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js | 2 ++ .../suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js | 3 +++ Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js | 1 + 6 files changed, 9 insertions(+) diff --git a/Website/test/e2e/suite/500_duplicate/Duplicate.js b/Website/test/e2e/suite/500_duplicate/Duplicate.js index df33e235cb..ef9f365527 100644 --- a/Website/test/e2e/suite/500_duplicate/Duplicate.js +++ b/Website/test/e2e/suite/500_duplicate/Duplicate.js @@ -19,6 +19,7 @@ module.exports = { .selectPerspective("Content") .selectTreeNodeAction("Copy of Getting Started","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("Copy of Getting Started") }, afterEach: function (browser, done) { done(); diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js index be0d95f9bb..d1665ec59e 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithAction.js @@ -29,6 +29,7 @@ module.exports = { .selectPerspective("Content") .selectTreeNodeAction("Copy of Blog","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("Copy of Blog") }, afterEach: function (browser, done) { done(); diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js index 2b435236e7..ed24b60bcc 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithData.js @@ -25,6 +25,7 @@ module.exports = { .selectPerspective("Content") .selectTreeNodeAction("Copy of Venus Starter Site","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("Copy of Venus Starter Site") }, diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js index 50b05dab36..bd0a83a02a 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaData.js @@ -40,9 +40,11 @@ module.exports = { .clickDialogButton("OK") .selectTreeNodeAction("Copy of Getting Started","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("Copy of Getting Started") .selectPerspective("Data") .selectTreeNodeAction("newNamespace.myTypeName","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("newNamespace.myTypeName") }, diff --git a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js index b503b6cc10..2f5b4cbd32 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicatePagesWithMetaDataOnType.js @@ -51,15 +51,18 @@ module.exports = { .selectTreeNodeAction("Getting Started","Publish") .selectTreeNodeAction("Copy of Getting Started","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("Copy of Getting Started") .selectPerspective("Layout") .openTreeNode("Metadata Fields") .selectTreeNodeAction("newName","Delete Metadata Field") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("newName") .selectPerspective("Data") .selectTreeNodeAction("newNamespace.myTypeName","Delete") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("newNamespace.myTypeName") }, afterEach: function (browser, done) { diff --git a/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js b/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js index dcede706af..5b3e4e5306 100644 --- a/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js +++ b/Website/test/e2e/suite/500_duplicate/DuplicateTreeAction.js @@ -29,6 +29,7 @@ module.exports = { .selectPerspective("Content") .selectTreeNodeAction("Copy of About this blog","Delete Blog Entry") .clickDialogButton("OK") + .assertTreeNodeHasNoChild("2014 June","Copy of About this blog") .selectPerspective("System") .selectTreeNodeAction("Composite.Community.Blog.Entries.xml","Edit File") .replaceTextInCodeMirror('','') From 809912bf87f07dfb1990162097a9c6a297378b3e Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 21 Sep 2016 15:23:15 +0200 Subject: [PATCH 49/95] fix for install sql package --- Website/test/e2e/suite/000_setup/InstalSQLPackage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js index 6eb9a8d98a..ecf9e79557 100644 --- a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -30,10 +30,10 @@ module.exports = { .setFieldValue("Connection String:",browser.globals.connectionString) .submitFormData('Next') .submitFormData('Finish') + .selectFrameWithXpath('//*[local-name()="span"][contains(.,"completed")]') + .useXpath() + .waitForElementPresent('//*[local-name()="span"][contains(.,"completed")]',browser.globals.timeouts.save) - .selectPerspective("System") - .assertTreeNodeHasNoChild("SqlServer Data Provider") - }, afterEach: function (browser, done) { done(); From 28fa7506f85407c30fc98a11b8d09da9d6766ce0 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Thu, 22 Sep 2016 13:15:00 +0200 Subject: [PATCH 50/95] fix install sql package wait for completion bug --- .../test/e2e/commands/clickDialogButton.js | 2 +- Website/test/e2e/commands/selectDialog.js | 16 -------------- Website/test/e2e/commands/waitForDialog.js | 15 +++++++++++++ .../e2e/commands/waitForFrameLoadwithXpath.js | 22 +++++++++++++++++-- .../e2e/suite/000_setup/InstalSQLPackage.js | 16 +++++++++++--- 5 files changed, 49 insertions(+), 22 deletions(-) delete mode 100644 Website/test/e2e/commands/selectDialog.js create mode 100644 Website/test/e2e/commands/waitForDialog.js diff --git a/Website/test/e2e/commands/clickDialogButton.js b/Website/test/e2e/commands/clickDialogButton.js index cf2e936e7f..1bce3a7b2d 100644 --- a/Website/test/e2e/commands/clickDialogButton.js +++ b/Website/test/e2e/commands/clickDialogButton.js @@ -9,7 +9,7 @@ util.inherits(ClickOnDialogButton, events.EventEmitter); ClickOnDialogButton.prototype.command = function (button) { this.client.api - .selectFrame('#dialogbuttonstoolbar') + .selectFrame('clickbutton[label="' + button + '"]') .waitForElementVisible('clickbutton[label="' + button + '"]', this.api.globals.timeouts.basic) .click('clickbutton[label="'+button+'"]', () => this.emit('complete')) return this.client.api; diff --git a/Website/test/e2e/commands/selectDialog.js b/Website/test/e2e/commands/selectDialog.js deleted file mode 100644 index d9f4b96c6d..0000000000 --- a/Website/test/e2e/commands/selectDialog.js +++ /dev/null @@ -1,16 +0,0 @@ -var events = require('events'); - -function SelectDialog() { - events.EventEmitter.call(this); -} - -SelectDialog.prototype.command = function (tabName) { - this.client.api.selectFrameWithXpath('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]'); - this.client.api - .useXpath() - .click('//*[local-name() = "dialoghead"]/*//*[local-name() = "labeltext"][normalize-space(text())="'+tabName+'"]').useCss() - - return this.client.api; -}; - -module.exports = SelectDialog; \ No newline at end of file diff --git a/Website/test/e2e/commands/waitForDialog.js b/Website/test/e2e/commands/waitForDialog.js new file mode 100644 index 0000000000..b827273aca --- /dev/null +++ b/Website/test/e2e/commands/waitForDialog.js @@ -0,0 +1,15 @@ +var events = require('events'); + +function SelectDialog() { + events.EventEmitter.call(this); +} + +SelectDialog.prototype.command = function (timeout) { + this.client.api.page.appWindow().enter(); + this.client.api.waitForFrameLoad('iframe[src*="/Composite/content/dialogs/standard/standard.aspx"]',timeout) + //this.client.api.waitForFrameLoad('iframe[src*="/Composite/content/flow/FlowUi.aspx"]',timeout); + + return this.client.api; +}; + +module.exports = SelectDialog; \ No newline at end of file diff --git a/Website/test/e2e/commands/waitForFrameLoadwithXpath.js b/Website/test/e2e/commands/waitForFrameLoadwithXpath.js index 96c4f837a7..50d1c197e3 100644 --- a/Website/test/e2e/commands/waitForFrameLoadwithXpath.js +++ b/Website/test/e2e/commands/waitForFrameLoadwithXpath.js @@ -29,8 +29,26 @@ WaitForFrameLoad.prototype.command = function(selector, timeout) { function checkFrameLoaded() { client.api.execute(function (selector) { - var frame = document.evaluate('count('+selector+')',document,null,XPathResult.ANY_TYPE,null); - return frame.numberValue > 0; + function search(selector, frames) { + var i, childFrame, selection; + for (i = 0; i < frames.length; i++) { + try { + childFrame = frames[i]; + alert(childFrame.name || 'unnamed' + ' ' + i); + selection = childFrame.document.evaluate('count('+selector+')',document,null,XPathResult.ANY_TYPE,null); + if(selection.numberValue > 0){ + return true; + } + if(childFrame.length>0){ + search(selector,childFrame); + } + } catch (e) { + //alert(e.message); + } + } + return false; + } + return search(selector, window); }, [selector], (result) => { if (result.value === true) { clearTimeout(timeoutTimer); diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js index ecf9e79557..a7fcc7b248 100644 --- a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -25,14 +25,24 @@ module.exports = { .openTreeNode("Installed Packages","Composite.Tools") .assertTreeNodeHasChild("Composite.Tools","Composite.Tools.SqlServerDataProvider") + .openTreeNode("/") + .openTreeNode("Composite") + .openTreeNode("Composite","InstalledPackages") + .openTreeNode("InstalledPackages","content") + .openTreeNode("content","views") + .openTreeNode("views","Composite.Tools.SqlServerDataProvider") + .selectTreeNodeAction("SqlServerDataProvider.aspx.cs","Edit File") + .replaceTextInCodeMirror('ConsoleMessageQueueFacade.Enqueue(new RebootConsoleMessageQueueItem(), null);','//ConsoleMessageQueueFacade.Enqueue(new RebootConsoleMessageQueueItem(), null);') + .clickSave() + .closeDocumentTab("SqlServerDataProvider.aspx.cs") + .selectTreeNodeAction("SqlServer Data Provider","Convert to SQL") .selectDocumentTab("Convert to SQL") .setFieldValue("Connection String:",browser.globals.connectionString) .submitFormData('Next') .submitFormData('Finish') - .selectFrameWithXpath('//*[local-name()="span"][contains(.,"completed")]') - .useXpath() - .waitForElementPresent('//*[local-name()="span"][contains(.,"completed")]',browser.globals.timeouts.save) + .waitForDialog(browser.globals.timeouts.save) + .refresh() }, afterEach: function (browser, done) { From 0f7387bc0f2ea7957db5114997c7138e411dd23f Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Thu, 22 Sep 2016 15:23:04 +0200 Subject: [PATCH 51/95] add waits before selecting perspective --- Website/test/e2e/pageObjects/content.js | 2 +- Website/test/e2e/suite/000_setup/installSite.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index 4654230f9e..b9b5f372da 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -25,7 +25,7 @@ module.exports = { .enter() .waitForElementNotPresent('dialogcover[hidden="true"]', this.api.globals.timeouts.basic) .waitForElementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]', this.api.globals.timeouts.basic) - .api.pause(200) + .api.pause(this.api.globals.timeouts.basic) .click('#explorer explorertoolbarbutton[label="'+perspective+'"]') .waitForFrameLoad('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe', this.api.globals.timeouts.basic) .enterFrame('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe'); diff --git a/Website/test/e2e/suite/000_setup/installSite.js b/Website/test/e2e/suite/000_setup/installSite.js index 2905924198..e5abe79da6 100644 --- a/Website/test/e2e/suite/000_setup/installSite.js +++ b/Website/test/e2e/suite/000_setup/installSite.js @@ -126,6 +126,6 @@ module.exports = { .waitForElementNotPresent('#loading', browser.globals.timeouts.save) .waitForElementVisible('body', browser.globals.timeouts.basic) .page.appWindow() - .waitForFrameLoad('@appFrame', browser.globals.timeouts.little); + .waitForFrameLoad('@appFrame', browser.globals.timeouts.basic); } } From ad66ad98bbbe27c0be0d89a883365272c025f71d Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Thu, 22 Sep 2016 17:55:25 +0200 Subject: [PATCH 52/95] add preparing before selecting perspective, remove big timeout --- Website/test/e2e/commands/selectPerspective.js | 4 +++- Website/test/e2e/pageObjects/content.js | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Website/test/e2e/commands/selectPerspective.js b/Website/test/e2e/commands/selectPerspective.js index c0f973828d..c3bcd59df7 100644 --- a/Website/test/e2e/commands/selectPerspective.js +++ b/Website/test/e2e/commands/selectPerspective.js @@ -6,9 +6,11 @@ function SelectPerspective() { SelectPerspective.prototype.command = function (perspective) { var content = this.client.api.page.content(); + content.waitForBrowserFrame(perspective); var systemView = this.client.api.page.systemView(); systemView - .enter(perspective); + .enter(perspective) + return this.client.api; }; diff --git a/Website/test/e2e/pageObjects/content.js b/Website/test/e2e/pageObjects/content.js index b9b5f372da..b69a1bb663 100644 --- a/Website/test/e2e/pageObjects/content.js +++ b/Website/test/e2e/pageObjects/content.js @@ -18,14 +18,11 @@ module.exports = { commands: [ { enter: function (perspective) { - if(perspective==null){ - perspective = "Content"; // for backward compatibility - } + perspective = perspective || "Content"; // for backward compatibility this.api.page.appWindow() .enter() .waitForElementNotPresent('dialogcover[hidden="true"]', this.api.globals.timeouts.basic) .waitForElementPresent('#explorer explorertoolbarbutton[label="'+perspective+'"]', this.api.globals.timeouts.basic) - .api.pause(this.api.globals.timeouts.basic) .click('#explorer explorertoolbarbutton[label="'+perspective+'"]') .waitForFrameLoad('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe', this.api.globals.timeouts.basic) .enterFrame('#stagedecks stagedeck[data-qa*="'+perspective+'"] iframe'); @@ -45,6 +42,14 @@ module.exports = { .waitForFrameLoad('@browserFrame', this.api.globals.timeouts.basic); return this; }, + waitForBrowserFrame: function (perspective) { + perspective = perspective || "Content"; // for backward compatibility + this + .enter(perspective) + .waitForElementVisible('@browserFrame', this.api.globals.timeouts.basic) + .waitForFrameLoad('@browserFrame', this.api.globals.timeouts.basic); + return this; + }, enterTabFrame: function (index) { this .enter() From 1fd3a9f148d25ea5c26e7323b6d3b6443dff97c1 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Thu, 22 Sep 2016 18:12:48 +0200 Subject: [PATCH 53/95] add a pause after package installation so reload does not interfere next operation --- Website/test/e2e/suite/000_setup/InstalSQLPackage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js index a7fcc7b248..4e1b33a424 100644 --- a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -18,6 +18,7 @@ module.exports = { .clickDialogButton("Next") .clickDialogButton("Next") .clickDialogButton("Finish") + .pause(2000) browser .selectPerspective("System") From 8161fcb5a38752c3a1b0d02b403cd6435a2a6117 Mon Sep 17 00:00:00 2001 From: Marcus Wendt Date: Fri, 23 Sep 2016 14:20:40 +0200 Subject: [PATCH 54/95] More "Composite C1" to "Orckestra CMS" string replacements. --- .../Web/Html/Template/CommonMetaTagsFunction.cs | 2 +- .../ConfigBasedGlobalSettingsProvider.cs | 2 +- Website/App_Data/Composite/DebugBuild.Composite.config | 2 +- Website/App_Data/Composite/ReleaseBuild.Composite.config | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs b/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs index bcf4fec837..2a0d6d2e06 100644 --- a/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs +++ b/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/Web/Html/Template/CommonMetaTagsFunction.cs @@ -73,7 +73,7 @@ public override object Execute(ParameterList parameters, FunctionContextContaine { metaTags.Add(new XElement(Namespaces.Xhtml + "meta", new XAttribute("name", "Generator"), - new XAttribute("content", "Orckestra CMS CMS - Free Open Source from http://composite.net/"))); + new XAttribute("content", "Orckestra CMS Foundation - Free Open Source from Orckestra and https://github.com/Orckestra/CMS-Foundation"))); } return metaTags; diff --git a/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs b/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs index 7b12fb5132..df0503360f 100644 --- a/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs +++ b/Composite/Plugins/GlobalSettings/GlobalSettingsProviders/ConfigBasedGlobalSettingsProvider.cs @@ -347,7 +347,7 @@ public string ApplicationName } private const string _applicationShortNamePropertyName = "applicationShortName"; - [ConfigurationProperty(_applicationShortNamePropertyName, IsRequired = true, DefaultValue = "C1")] + [ConfigurationProperty(_applicationShortNamePropertyName, IsRequired = true, DefaultValue = "CMS")] public string ApplicationShortName { get { return (string)base[_applicationShortNamePropertyName]; } diff --git a/Website/App_Data/Composite/DebugBuild.Composite.config b/Website/App_Data/Composite/DebugBuild.Composite.config index 6c0a50a453..b84a94f52c 100644 --- a/Website/App_Data/Composite/DebugBuild.Composite.config +++ b/Website/App_Data/Composite/DebugBuild.Composite.config @@ -69,7 +69,7 @@ Date: Fri, 23 Sep 2016 17:00:52 +0200 Subject: [PATCH 55/95] making set value in login test more stable --- Website/test/e2e/pageObjects/login.js | 8 ++++++-- Website/test/e2e/suite/100_login/procedure.js | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Website/test/e2e/pageObjects/login.js b/Website/test/e2e/pageObjects/login.js index a88ce37dc7..0c421103e4 100644 --- a/Website/test/e2e/pageObjects/login.js +++ b/Website/test/e2e/pageObjects/login.js @@ -16,13 +16,17 @@ module.exports = { setUsername: function (username) { this .clearValue('@usernameInput') // There may be a default value, clear it - .setValue('@usernameInput', username); + .click('@usernameInput') + .setValue('@usernameInput', username) + .assert.value('@usernameInput',username); return this; }, setPassword: function (password) { this .clearValue('@passwordInput') // There may be a default value, clear it - .setValue('@passwordInput', password); + .click('@passwordInput') + .setValue('@passwordInput', password) + .assert.value('@passwordInput', password); return this; }, fullLogin: function (username, password) { diff --git a/Website/test/e2e/suite/100_login/procedure.js b/Website/test/e2e/suite/100_login/procedure.js index 474585983c..d1f039402e 100644 --- a/Website/test/e2e/suite/100_login/procedure.js +++ b/Website/test/e2e/suite/100_login/procedure.js @@ -4,6 +4,7 @@ module.exports = { login = browser.page.login(); startScreen = browser.page.startScreen(); login + .isShown() .setUsername('admin') .setPassword('123456') .click('@submitButton') From 254bf83e57365244eb979587d1015c71b29d937d Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 26 Sep 2016 11:03:50 +0200 Subject: [PATCH 56/95] fix bug #13 => actual bug: when data elements placed at the root of tree children won't show up --- Composite/C1Console/Trees/DataElementsTreeNode.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Composite/C1Console/Trees/DataElementsTreeNode.cs b/Composite/C1Console/Trees/DataElementsTreeNode.cs index d167d0ad10..54b689e032 100644 --- a/Composite/C1Console/Trees/DataElementsTreeNode.cs +++ b/Composite/C1Console/Trees/DataElementsTreeNode.cs @@ -6,6 +6,7 @@ using System.Reflection; using Composite.C1Console.Elements; using Composite.C1Console.Security; +using Composite.C1Console.Trees.Foundation; using Composite.C1Console.Users; using Composite.C1Console.Workflow; using Composite.Core.Extensions; @@ -226,6 +227,10 @@ EntityToken parentEntityToken dynamicContext.Piggybag.PreparePiggybag(this.ParentNode, parentEntityToken) )); + if (parentEntityToken is TreePerspectiveEntityToken) + { + element.ElementHandle.Piggyback[StringConstants.PiggybagTreeId] = Tree.TreeId; + } bool hasChildren; bool isDisabled = false; From f7a30a0154cf8779cac7bebbac4c64c94e389624 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Mon, 26 Sep 2016 15:26:59 +0200 Subject: [PATCH 57/95] fix bug #220 --- .../content/dialogs/standard/StandardDialogPageBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website/Composite/content/dialogs/standard/StandardDialogPageBinding.js b/Website/Composite/content/dialogs/standard/StandardDialogPageBinding.js index b30b6f7ac5..ad2bae92a9 100644 --- a/Website/Composite/content/dialogs/standard/StandardDialogPageBinding.js +++ b/Website/Composite/content/dialogs/standard/StandardDialogPageBinding.js @@ -63,7 +63,7 @@ StandardDialogPageBinding.prototype.onBeforePageInitialize = function () { var divDialogText = document.getElementById("dialogtext"); - var text = this._dialogText.replace('\r\n', '\n'); + var text = (this._dialogText == null) ? "" : this._dialogText.replace('\r\n', '\n'); var textParts = text.split('\n'); // Adding text and inserting and inserting line breaks From 0dd99039237361aedbc4f5ff4de51f47a5970967 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Tue, 27 Sep 2016 14:48:00 +0200 Subject: [PATCH 58/95] fix bug #239 : DynamicDataTypePackageFragmentInstaller compatibility with older packages --- .../DynamicDataTypePackageFragmentInstaller.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Composite/Core/PackageSystem/PackageFragmentInstallers/DynamicDataTypePackageFragmentInstaller.cs b/Composite/Core/PackageSystem/PackageFragmentInstallers/DynamicDataTypePackageFragmentInstaller.cs index 87234ba265..e95f838baa 100644 --- a/Composite/Core/PackageSystem/PackageFragmentInstallers/DynamicDataTypePackageFragmentInstaller.cs +++ b/Composite/Core/PackageSystem/PackageFragmentInstallers/DynamicDataTypePackageFragmentInstaller.cs @@ -7,6 +7,7 @@ using Composite.Data.GeneratedTypes; using Composite.Core.Extensions; using Composite.Core.Types; +using Composite.Data.Types; namespace Composite.Core.PackageSystem.PackageFragmentInstallers @@ -84,6 +85,14 @@ public override IEnumerable Validate() validationResult.AddFatal(GetText("DynamicDataTypePackageFragmentInstaller.TypeExists").FormatWith(type)); } + if (dataTypeDescriptor.SuperInterfaces.Any(f=>f.Name==nameof(IVersioned))) + { + if (dataTypeDescriptor.Fields.All(f => f.Name != nameof(IVersioned.VersionId))) + { + dataTypeDescriptor.Fields.Add(new DataFieldDescriptor(Guid.NewGuid(), nameof(IVersioned.VersionId),StoreFieldType.Guid, typeof(Guid),true )); + } + } + foreach (var field in dataTypeDescriptor.Fields) { if(!field.ForeignKeyReferenceTypeName.IsNullOrEmpty()) From e1ff77cc410cb1352224bc76af645f9f6c6afb6f Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 28 Sep 2016 11:51:06 +0200 Subject: [PATCH 59/95] Adding a layer of abstraction for package installation , change the wait time after package installation to 5 second --- .../test/e2e/ApiLang/Notepad++/Nightwatch.UDL | 2 +- .../test/e2e/ApiLang/Notepad++/nightwatch.xml | 12 +++++++ Website/test/e2e/commands/installPackage.js | 31 +++++++++++++++++++ Website/test/e2e/commands/uninstallPackage.js | 24 ++++++++++++++ .../e2e/suite/000_setup/InstalSQLPackage.js | 15 +-------- 5 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 Website/test/e2e/commands/installPackage.js create mode 100644 Website/test/e2e/commands/uninstallPackage.js diff --git a/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL b/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL index 668c5762cf..d84c0ba2c7 100644 --- a/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL +++ b/Website/test/e2e/ApiLang/Notepad++/Nightwatch.UDL @@ -24,7 +24,7 @@ - assertBrowserContainsAttribute assertBrowserContains assertFieldValue assertTreeNodeHasChild assertTreeNodeIsEmpty assertTreeNodeIsNotEmpty clickDataBySibilings clickDialogButton clickInFrame clickLabel clickSave replaceTextInCodeMirror selectEditOnContent clickText closeDocumentTab changeElementContent doubleClickSelector enterFrame leaveFrame openTreeNode replaceContent rightClickSelector selectActionFromToolbar selectContentTab selectDialog selectDocumentTab selectFrame selectFrameWithXpath selectPerspective selectTreeNodeAction setFieldValueInFieldGroup setFieldValue switchContentTab topFrame waitForFrameLoad acceptChanges acceptFunctionEdit assertTreeNodeHasNoChild submitFormData + assertBrowserContainsAttribute assertBrowserContains assertFieldValue assertTreeNodeHasChild assertTreeNodeIsEmpty assertTreeNodeIsNotEmpty clickDataBySibilings clickDialogButton clickInFrame clickLabel clickSave replaceTextInCodeMirror selectEditOnContent clickText closeDocumentTab changeElementContent doubleClickSelector enterFrame leaveFrame openTreeNode replaceContent rightClickSelector selectActionFromToolbar selectContentTab selectDialog selectDocumentTab selectFrame selectFrameWithXpath selectPerspective selectTreeNodeAction setFieldValueInFieldGroup setFieldValue switchContentTab topFrame waitForFrameLoad acceptChanges acceptFunctionEdit assertTreeNodeHasNoChild submitFormData installPackage uninstallPackage browser editor2 editor beforeEach afterEach done diff --git a/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml b/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml index b94e82f4bf..3bccb54b1d 100644 --- a/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml +++ b/Website/test/e2e/ApiLang/Notepad++/nightwatch.xml @@ -218,5 +218,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Website/test/e2e/commands/installPackage.js b/Website/test/e2e/commands/installPackage.js new file mode 100644 index 0000000000..d7da5e12fe --- /dev/null +++ b/Website/test/e2e/commands/installPackage.js @@ -0,0 +1,31 @@ +var events = require('events'); + +function InstallPackage() { + events.EventEmitter.call(this); +} + +InstallPackage.prototype.command = function (category,packageName) { + this.client.api + .selectPerspective("System") + .openTreeNode("Available Packages") + .openTreeNode(category) + .selectTreeNodeAction(packageName, "Install") + .clickLabel("I accept the license agreement") + .clickDialogButton("Next") + .clickDialogButton("Next") + .clickDialogButton("Next") + .clickDialogButton("Finish") + .pause(5000) + .refresh() + + this.client.api + .selectPerspective("System") + .openTreeNode("Packages","Installed Packages") + .openTreeNode("Installed Packages",category) + .assertTreeNodeHasChild(category,packageName) + .refresh() + + return this.client.api; +}; + +module.exports = InstallPackage; diff --git a/Website/test/e2e/commands/uninstallPackage.js b/Website/test/e2e/commands/uninstallPackage.js new file mode 100644 index 0000000000..59701e61e0 --- /dev/null +++ b/Website/test/e2e/commands/uninstallPackage.js @@ -0,0 +1,24 @@ +var events = require('events'); + +function InstallPackage() { + events.EventEmitter.call(this); +} + +InstallPackage.prototype.command = function (category,packageName) { + this.client.api + .selectPerspective("System") + .openTreeNode("Packages","Installed Packages") + .openTreeNode("Installed Packages",category) + .assertTreeNodeHasChild(category,packageName) + .selectTreeNodeAction(packageName,"Package Info") + .clickLabel("Uninstall") + .clickDialogButton("Next") + .clickDialogButton("Next") + .clickDialogButton("Finish") + .pause(5000) + .refresh() + + return this.client.api; +}; + +module.exports = InstallPackage; diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js index 4e1b33a424..d4d062b9c3 100644 --- a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js +++ b/Website/test/e2e/suite/000_setup/InstalSQLPackage.js @@ -9,23 +9,10 @@ module.exports = { 'Install SQL Package': function (browser) { browser - .selectPerspective("System") - .openTreeNode("Available Packages") - .openTreeNode("Composite.Tools") - .selectTreeNodeAction("Composite.Tools.SqlServerDataProvider", "Install") - .clickLabel("I accept the license agreement") - .clickDialogButton("Next") - .clickDialogButton("Next") - .clickDialogButton("Next") - .clickDialogButton("Finish") - .pause(2000) + .installPackage("Composite.Tools","Composite.Tools.SqlServerDataProvider") browser .selectPerspective("System") - .openTreeNode("Packages","Installed Packages") - .openTreeNode("Installed Packages","Composite.Tools") - .assertTreeNodeHasChild("Composite.Tools","Composite.Tools.SqlServerDataProvider") - .openTreeNode("/") .openTreeNode("Composite") .openTreeNode("Composite","InstalledPackages") From 2137ccaf9c6bac255805280b5825d7fc09e0a0e8 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 28 Sep 2016 11:52:00 +0200 Subject: [PATCH 60/95] Install verbose logging package from the beginning --- .../000_setup/InstallVerboseLoggingPackage.js | 18 ++++++++++++++++++ nightwatch.json | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js diff --git a/Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js b/Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js new file mode 100644 index 0000000000..cdf8f5212a --- /dev/null +++ b/Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js @@ -0,0 +1,18 @@ +module.exports = { + '@tags': ['InstallPackage'], + beforeEach: function (browser) { + browser.url(browser.launchUrl + '/Composite/top.aspx'); + var content = browser.page.content(); + content + .prepare(); + }, + 'Install Verbose Logging Package': function (browser) { + + browser + .installPackage("Composite.Tools","Composite.Tools.VerboseLogging") + + }, + afterEach: function (browser, done) { + done(); + } +} diff --git a/nightwatch.json b/nightwatch.json index 468d098123..1e33b74a25 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -51,7 +51,8 @@ }, "sql": { - "exclude" : ["Website/test/e2e/suite/000_setup/installSite.js"] + "exclude" : ["Website/test/e2e/suite/000_setup/installSite.js", + "Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js"] }, "firefox" : { From 33bf89e48effd5c537e226e74e07cc4e55240fa7 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Wed, 28 Sep 2016 12:07:46 +0200 Subject: [PATCH 61/95] Refactoring; System log weren't showing log messages if one of the log files were locked --- Composite/Core/Logging/LogManager.cs | 35 +++++-------------- Composite/Core/UrlBuilder.cs | 4 ++- .../PageElementProvider.cs | 3 +- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/Composite/Core/Logging/LogManager.cs b/Composite/Core/Logging/LogManager.cs index 0d56d1e9cc..c6d00a41f4 100644 --- a/Composite/Core/Logging/LogManager.cs +++ b/Composite/Core/Logging/LogManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Composite.C1Console.Events; using Composite.Plugins.Logging.LogTraceListeners.FileLogTraceListener; namespace Composite.Core.Logging @@ -28,29 +27,22 @@ static LogManager() FileLogger.OnReset += () => _logFiles = null; } - private static FileLogger FileLogger - { - get - { - return FileLogTraceListener.LoggerInstance; - } - } + private static FileLogger FileLogger => FileLogTraceListener.LoggerInstance; private static LogFileReader[] LogFiles { get { var result = _logFiles; - if (_logFiles == null || _logFiles.Length == 0) + if (result == null || result.Length == 0) { lock (_syncRoot) { - if (_logFiles == null || _logFiles.Length == 0) + result = _logFiles; + if (result == null || result.Length == 0) { - - _logFiles = (FileLogger != null ? FileLogger.GetLogFiles() : new LogFileReader[0]); + _logFiles = result = FileLogger?.GetLogFiles() ?? new LogFileReader[0]; } - result = _logFiles; } } return result; @@ -84,12 +76,7 @@ public static bool DeleteLogFile(DateTime date) internal static void Flush() { - var logger = FileLogger; - - if (logger != null) - { - logger.Flush(); - } + FileLogger?.Flush(); } @@ -119,13 +106,7 @@ public static int GetLogEntriesCountByDate(DateTime date, bool includeVerbose) { date = date.Date; - int result = 0; - foreach (var logFile in LogFiles.Where(logFile => logFile.Date == date)) - { - result += logFile.EntriesCount; - } - - return result; + return LogFiles.Where(logFile => logFile.Date == date).Sum(logFile => logFile.EntriesCount); } @@ -151,7 +132,7 @@ public static LogEntry[] GetLogEntries(DateTime timeFrom, DateTime timeTo, bool { if (!logFile.Open()) { - if (DateTime.Now - _startTime > LockedFileAwaitingPeriod) + if (DateTime.Now - _startTime < LockedFileAwaitingPeriod) { // Waiting for some time until all log files are released // This ensures that LogViewer will get all the logs from previous, currently being shutdown AppDomain(s) diff --git a/Composite/Core/UrlBuilder.cs b/Composite/Core/UrlBuilder.cs index 9b5a2e4218..73f030331a 100644 --- a/Composite/Core/UrlBuilder.cs +++ b/Composite/Core/UrlBuilder.cs @@ -21,12 +21,14 @@ public sealed class UrlBuilder private string _pathInfo; private string _filePath; private string _anchor; - private List> _queryParameters; + private readonly List> _queryParameters; /// public UrlBuilder(string url) { + Verify.ArgumentNotNull(url, nameof(url)); + _queryParameters = new List>(); int anchorIndex = url.IndexOf('#'); diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs index 669d215340..1c2b39bf87 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs @@ -721,7 +721,8 @@ private List GetElements(List> pag } }); - IPageType parentPageType = allPageTypes.First(f => f.Id == page.PageTypeId); + IPageType parentPageType = allPageTypes.FirstOrDefault(f => f.Id == page.PageTypeId); + Verify.IsNotNull(parentPageType, "Failed to find page type by id '{0}'", page.PageTypeId); foreach (var pageType in page.GetChildPageSelectablePageTypes().OrderByDescending(pt => pt.Id == parentPageType.DefaultChildPageType)) { From 4c3cd7235757d5f30593648db56b7cf417987c93 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 28 Sep 2016 13:12:54 +0200 Subject: [PATCH 62/95] moving package installation to its own folder in suit to be sure about order of execution --- .../{000_setup => 010_setupPackages}/InstalSQLPackage.js | 0 .../installVerboseLoggingPackage.js} | 0 Website/test/e2e/suite/{400_content => content}/browseTree.js | 0 .../test/e2e/suite/{400_content => content}/multiEditor.js | 0 .../test/e2e/suite/{400_content => content}/singleEditor.js | 0 nightwatch.json | 4 ++-- 6 files changed, 2 insertions(+), 2 deletions(-) rename Website/test/e2e/suite/{000_setup => 010_setupPackages}/InstalSQLPackage.js (100%) rename Website/test/e2e/suite/{000_setup/InstallVerboseLoggingPackage.js => 010_setupPackages/installVerboseLoggingPackage.js} (100%) rename Website/test/e2e/suite/{400_content => content}/browseTree.js (100%) rename Website/test/e2e/suite/{400_content => content}/multiEditor.js (100%) rename Website/test/e2e/suite/{400_content => content}/singleEditor.js (100%) diff --git a/Website/test/e2e/suite/000_setup/InstalSQLPackage.js b/Website/test/e2e/suite/010_setupPackages/InstalSQLPackage.js similarity index 100% rename from Website/test/e2e/suite/000_setup/InstalSQLPackage.js rename to Website/test/e2e/suite/010_setupPackages/InstalSQLPackage.js diff --git a/Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js b/Website/test/e2e/suite/010_setupPackages/installVerboseLoggingPackage.js similarity index 100% rename from Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js rename to Website/test/e2e/suite/010_setupPackages/installVerboseLoggingPackage.js diff --git a/Website/test/e2e/suite/400_content/browseTree.js b/Website/test/e2e/suite/content/browseTree.js similarity index 100% rename from Website/test/e2e/suite/400_content/browseTree.js rename to Website/test/e2e/suite/content/browseTree.js diff --git a/Website/test/e2e/suite/400_content/multiEditor.js b/Website/test/e2e/suite/content/multiEditor.js similarity index 100% rename from Website/test/e2e/suite/400_content/multiEditor.js rename to Website/test/e2e/suite/content/multiEditor.js diff --git a/Website/test/e2e/suite/400_content/singleEditor.js b/Website/test/e2e/suite/content/singleEditor.js similarity index 100% rename from Website/test/e2e/suite/400_content/singleEditor.js rename to Website/test/e2e/suite/content/singleEditor.js diff --git a/nightwatch.json b/nightwatch.json index 1e33b74a25..d40d990871 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -29,7 +29,7 @@ "silent": true, "end_session_on_fail": true, "skip_testcases_on_fail": false, - "exclude" : ["Website/test/e2e/suite/000_setup/InstalSQLPackage.js"], + "exclude" : ["Website/test/e2e/suite/010_setupPackages/InstalSQLPackage.js"], "globals": { "connectionString": "" }, @@ -52,7 +52,7 @@ "sql": { "exclude" : ["Website/test/e2e/suite/000_setup/installSite.js", - "Website/test/e2e/suite/000_setup/InstallVerboseLoggingPackage.js"] + "Website/test/e2e/suite/010_setupPackages/installVerboseLoggingPackage.js"] }, "firefox" : { From dc0c7e9f00c9a75d4b7c73a128184decc64c3e24 Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 28 Sep 2016 13:13:52 +0200 Subject: [PATCH 63/95] typo correction --- .../{InstalSQLPackage.js => installSQLPackage.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Website/test/e2e/suite/010_setupPackages/{InstalSQLPackage.js => installSQLPackage.js} (100%) diff --git a/Website/test/e2e/suite/010_setupPackages/InstalSQLPackage.js b/Website/test/e2e/suite/010_setupPackages/installSQLPackage.js similarity index 100% rename from Website/test/e2e/suite/010_setupPackages/InstalSQLPackage.js rename to Website/test/e2e/suite/010_setupPackages/installSQLPackage.js From e835c83ca4b265e98340643f8014c5f475020f5d Mon Sep 17 00:00:00 2001 From: Morteza Kasravi Date: Wed, 28 Sep 2016 13:44:12 +0200 Subject: [PATCH 64/95] bug fix --- nightwatch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightwatch.json b/nightwatch.json index d40d990871..cdfe958b35 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -29,7 +29,7 @@ "silent": true, "end_session_on_fail": true, "skip_testcases_on_fail": false, - "exclude" : ["Website/test/e2e/suite/010_setupPackages/InstalSQLPackage.js"], + "exclude" : ["Website/test/e2e/suite/010_setupPackages/installSQLPackage.js"], "globals": { "connectionString": "" }, From a26cc406a7bb4e27cb39ea347518d7696deb6c95 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Thu, 29 Sep 2016 10:36:08 +0200 Subject: [PATCH 65/95] Fix #241 A NullRef exception in page routing --- .../Plugins/Routing/Pages/DefaultPageUrlProvider.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs b/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs index 08542242d1..04ebaceb24 100644 --- a/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs +++ b/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs @@ -434,7 +434,7 @@ private PageUrlData ParsePagePath(string pagePath, PublicationScope publicationS string pathInfo = null; bool canBePublicUrl = true; - bool pathInfoExctracted = false; + bool pathInfoExtracted = false; if (!string.IsNullOrEmpty(UrlSuffix)) { @@ -446,13 +446,13 @@ private PageUrlData ParsePagePath(string pagePath, PublicationScope publicationS pathInfo = pagePath.Substring(suffixOffset + UrlSuffix.Length); pagePath = pagePath.Substring(0, suffixOffset); - pathInfoExctracted = true; + pathInfoExtracted = true; } else if (pagePath.EndsWith(UrlSuffix, StringComparison.OrdinalIgnoreCase)) { pagePath = pagePath.Substring(0, pagePath.Length - UrlSuffix.Length); - pathInfoExctracted = true; + pathInfoExtracted = true; } else { @@ -462,7 +462,7 @@ private PageUrlData ParsePagePath(string pagePath, PublicationScope publicationS if (canBePublicUrl) { - IPage page = TryGetPageByUrlTitlePath(pagePath, pathInfoExctracted, hostnameBinding, ref pathInfo); + IPage page = TryGetPageByUrlTitlePath(pagePath, pathInfoExtracted, hostnameBinding, ref pathInfo); if (page != null) { @@ -510,8 +510,8 @@ private static IPage TryGetPageByUrlTitlePath(string pagePath, bool pathInfoExtr { IPage rootPage = PageManager.GetPageById(hostnameBinding.HomePageId, true); - bool rootPageIsOmmited = rootPage != null && !hostnameBinding.IncludeHomePageInUrl || string.IsNullOrEmpty(rootPage.UrlTitle); - if (rootPageIsOmmited) + bool rootPageIsOmitted = rootPage != null && (!hostnameBinding.IncludeHomePageInUrl || string.IsNullOrEmpty(rootPage.UrlTitle)); + if (rootPageIsOmitted) { firstPage = FindMatchingPage(rootPage.Id, firstUrlTitle); } From d2f3c30cb1fe977b2148ec5e9aa3b0430fe53c45 Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Thu, 29 Sep 2016 13:03:31 +0200 Subject: [PATCH 66/95] Upgrade .Net Framework (#242) --- Composite.Workflows/Composite.Workflows.csproj | 2 +- Composite/Composite.csproj | 2 +- Website/DebugBuild.Web.config | 2 +- Website/ReleaseBuild.Web.config | 2 +- Website/WebSite.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Composite.Workflows/Composite.Workflows.csproj b/Composite.Workflows/Composite.Workflows.csproj index 4dd05d28d0..bb5e5534d7 100644 --- a/Composite.Workflows/Composite.Workflows.csproj +++ b/Composite.Workflows/Composite.Workflows.csproj @@ -11,7 +11,7 @@ Composite Composite.Workflows {14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - v4.5.1 + v4.6.1 512 SAK SAK diff --git a/Composite/Composite.csproj b/Composite/Composite.csproj index c1cc186267..20b0764abd 100644 --- a/Composite/Composite.csproj +++ b/Composite/Composite.csproj @@ -11,7 +11,7 @@ Composite {14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 - v4.5.1 + v4.6.1 SAK SAK SAK diff --git a/Website/DebugBuild.Web.config b/Website/DebugBuild.Web.config index 39c90470f8..7b55a9c56e 100644 --- a/Website/DebugBuild.Web.config +++ b/Website/DebugBuild.Web.config @@ -20,7 +20,7 @@ - + diff --git a/Website/ReleaseBuild.Web.config b/Website/ReleaseBuild.Web.config index 5a5e95a0e2..29d8a1bdd8 100644 --- a/Website/ReleaseBuild.Web.config +++ b/Website/ReleaseBuild.Web.config @@ -21,7 +21,7 @@ - + diff --git a/Website/WebSite.csproj b/Website/WebSite.csproj index a424a5a963..139f97ba7b 100644 --- a/Website/WebSite.csproj +++ b/Website/WebSite.csproj @@ -11,7 +11,7 @@ Library Composite Composite.Website - v4.5.1 + v4.6.1 SAK SAK SAK From 711f2887537112eb269b0704acc18830f1fd067c Mon Sep 17 00:00:00 2001 From: Dmitry Dzygin Date: Thu, 29 Sep 2016 15:14:30 +0200 Subject: [PATCH 67/95] Fix #231 "Can't change the page type on pages" --- Composite/Data/Types/IPageType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composite/Data/Types/IPageType.cs b/Composite/Data/Types/IPageType.cs index 3bc4c034df..7fb2a3e258 100644 --- a/Composite/Data/Types/IPageType.cs +++ b/Composite/Data/Types/IPageType.cs @@ -83,7 +83,7 @@ public static IEnumerable GetChildPageSelectablePageTypes(this IPage pageTypes = pageTypes .Where(f => f.HomepageRelation != nameof(PageTypeHomepageRelation.OnlyHomePages) - && (childPage == null || f.Id == childPage.PageTypeId)) + || (childPage != null && f.Id == childPage.PageTypeId)) .Evaluate(); ICollection parentRestrictions = null; From d73f1e1e101d703ff102528951f564649f6da744 Mon Sep 17 00:00:00 2001 From: Inna Boitsun Date: Thu, 29 Sep 2016 19:08:18 +0300 Subject: [PATCH 68/95] Login and About pages with new Orckestra Logo --- Website/Composite/Login.aspx | 4 +-- .../content/branding/about-company.inc | 9 +++---- Website/Composite/content/branding/logo.inc | 4 ++- .../Composite/content/dialogs/about/about.css | 9 +++---- Website/Composite/images/logo-dark.png | Bin 0 -> 12073 bytes Website/Composite/images/logo.png | Bin 5736 -> 7080 bytes .../Composite/styles/default/branding.less | 23 ++++++++++++++---- 7 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 Website/Composite/images/logo-dark.png diff --git a/Website/Composite/Login.aspx b/Website/Composite/Login.aspx index 8806256adf..9a0e77e375 100644 --- a/Website/Composite/Login.aspx +++ b/Website/Composite/Login.aspx @@ -8,7 +8,7 @@ <% Response.WriteFile("favicon.inc"); %>