public PageComponentPipeBind(string nameOrId) { _component = null; if (!Guid.TryParse(nameOrId, out _id)) { _name = nameOrId; } }
/// <summary> /// Write the report to SharePoint /// </summary> /// <param name="clearLogData">Also clear the log data</param> public override void Flush(bool clearLogData) { try { if (_clientContext == null) { throw new ArgumentNullException("ClientContext is null"); } var report = GenerateReportWithSummaryAtTop(includeHeading: false); // Dont want to assume locality here string logRunTime = _reportDate.ToString().Replace('/', '-').Replace(":", "-").Replace(" ", "-"); string logFileName = $"Page-Transformation-Report-{logRunTime}{_reportFileName}"; logFileName = logFileName + ".aspx"; var targetFolder = this.EnsureDestination(); var pageName = $"{targetFolder.Name}/{logFileName}"; var reportPage = this._clientContext.Web.AddClientSidePage(pageName); reportPage.PageTitle = base._includeVerbose ? LogStrings.Report_ModernisationReport : LogStrings.Report_ModernisationSummaryReport; var componentsToAdd = CacheManager.Instance.GetClientSideComponents(_clientContext, reportPage); PnPCore.IPageComponent baseControl = null; var webPartName = reportPage.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.MarkDown); baseControl = componentsToAdd.FirstOrDefault(p => p.Name.Equals(webPartName, StringComparison.InvariantCultureIgnoreCase)); var jsonRpt = JsonConvert.SerializeObject(report, new JsonSerializerSettings { StringEscapeHandling = StringEscapeHandling.EscapeHtml }); var jsonDecoded = GetMarkdownJsonProperties(jsonRpt); //PnP.Framework.Pages.ClientSideWebPart mdWebPart = new PnP.Framework.Pages.ClientSideWebPart(baseControl) //{ // PropertiesJson = jsonDecoded //}; var mdWebPart = reportPage.NewWebPart(baseControl); mdWebPart.PropertiesJson = jsonDecoded; // This should only have one web part on the page reportPage.AddControl(mdWebPart); reportPage.Save(pageName); reportPage.DisableComments(); // Cleardown all logs Logs.RemoveRange(0, Logs.Count); Console.WriteLine($"Report saved as: {pageName}"); } catch (Exception ex) { Console.WriteLine("Error writing to log file: {0} {1}", ex.Message, ex.StackTrace); } }
internal PnPCore.IPageComponent GetComponent(PnPCore.IPage page) { if (_component != null) { return(_component); } else if (!string.IsNullOrEmpty(_name)) { PnPCore.IPageComponent com = page.AvailablePageComponents(_name).FirstOrDefault(); return(com); } else if (_id != Guid.Empty) { string idAsString = _id.ToString(); var comQuery = from c in page.AvailablePageComponents(_name) where c.Id == idAsString select c; return(comQuery.FirstOrDefault()); } else { return(null); } }
public PageComponentPipeBind(Guid id) { _id = id; _name = null; _component = null; }
public PageComponentPipeBind(PnPCore.IPageComponent component) { _component = component; _id = Guid.Parse(_component.Id); _name = _component.Name; }
/// <summary> /// Transforms the passed web parts into the loaded client side page /// </summary> /// <param name="webParts">List of web parts that need to be transformed</param> public void Transform(List <WebPartEntity> webParts) { LogInfo(LogStrings.ContentTransformingWebParts, LogStrings.Heading_ContentTransform); if (webParts == null || webParts.Count == 0) { // nothing to transform LogWarning(LogStrings.NothingToTransform, LogStrings.Heading_ContentTransform); return; } // find the default mapping, will be used for webparts for which the model does not contain a mapping var defaultMapping = pageTransformation.BaseWebPart.Mappings.Mapping.Where(p => p.Default == true).FirstOrDefault(); if (defaultMapping == null) { LogError(LogStrings.Error_NoDefaultMappingFound, LogStrings.Heading_ContentTransform); throw new Exception(LogStrings.Error_NoDefaultMappingFound); } // Load existing available controls var componentsToAdd = CacheManager.Instance.GetClientSideComponents(targetClientContext, page); if (this.transformationInformation.SourcePage != null && !this.transformationInformation.SourcePage.PageType().Equals("WebPartPage", StringComparison.InvariantCultureIgnoreCase)) { // Normalize row numbers as there can be gaps if the analyzed page contained wiki tables int newRowOrder = 0; int lastExistingRowOrder = -1; foreach (var webPart in webParts.OrderBy(p => p.Row)) { if (lastExistingRowOrder < webPart.Row) { newRowOrder++; lastExistingRowOrder = webPart.Row; } webPart.Row = newRowOrder; } } // Iterate over the web parts, important to order them by row, column and zoneindex foreach (var webPart in webParts.OrderBy(p => p.Row).ThenBy(p => p.Column).ThenBy(p => p.Order)) { LogInfo(string.Format(LogStrings.ContentWebPartBeingTransformed, webPart.Title, webPart.TypeShort()), LogStrings.Heading_MappingWebParts); // Title bar will never be migrated if (webPart.Type == WebParts.TitleBar) { LogInfo(LogStrings.NotTransformingTitleBar, LogStrings.Heading_MappingWebParts); continue; } // Assign the default mapping, if we're a more specific mapping than that will overwrite this mapping Mapping mapping = defaultMapping; // Does the web part have a mapping defined? // Older version of SharePoint var webPartData = pageTransformation.WebParts.Where(p => p.Type.GetTypeShort() == webPart.Type.GetTypeShort()).FirstOrDefault(); // Check for cross site transfer support if (webPartData != null && this.isCrossSiteTransfer) { if (!webPartData.CrossSiteTransformationSupported) { LogWarning(LogStrings.CrossSiteNotSupported, LogStrings.Heading_MappingWebParts); continue; } } if (webPartData != null && webPartData.Mappings != null) { // Add site level (e.g. site) tokens to the web part properties and model so they can be used in the same manner as a web part property UpdateWebPartDataProperties(webPart, webPartData, this.globalTokens); string selectorResult = null; try { // The mapping can have a selector function defined, is so it will be executed. If a selector was executed the selectorResult will contain the name of the mapping to use LogDebug(LogStrings.ProcessingSelectorFunctions, LogStrings.Heading_MappingWebParts); selectorResult = functionProcessor.Process(ref webPartData, webPart); } catch (Exception ex) { // NotAvailableAtTargetException is used to "skip" a web part since it's not valid for the target site collection (only applies to cross site collection transfers) if (ex.InnerException is NotAvailableAtTargetException) { LogError(LogStrings.Error_NotValidForTargetSiteCollection, LogStrings.Heading_MappingWebParts, ex, true); continue; } if (ex.InnerException is MediaWebpartConfigurationException) { LogError(LogStrings.Error_MediaWebpartConfiguration, LogStrings.Heading_MappingWebParts, ex, true); continue; } LogError($"{LogStrings.Error_AnErrorOccurredFunctions} - {ex.Message}", LogStrings.Heading_MappingWebParts, ex); throw; } Mapping webPartMapping = null; // Get the needed mapping: // - use the mapping returned by the selector // - if no selector then take the default mapping // - if no mapping found we'll fall back to the default web part mapping if (!string.IsNullOrEmpty(selectorResult)) { webPartMapping = webPartData.Mappings.Mapping.Where(p => p.Name.Equals(selectorResult, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } else { // If there's only one mapping let's take that one, even if not specified as default if (webPartData.Mappings.Mapping.Length == 1) { webPartMapping = webPartData.Mappings.Mapping[0]; } else { webPartMapping = webPartData.Mappings.Mapping.Where(p => p.Default == true).FirstOrDefault(); } } if (webPartMapping != null) { mapping = webPartMapping; } else { LogWarning(LogStrings.ContentWebPartMappingNotFound, LogStrings.Heading_MappingWebParts); } // Process mapping specific functions (if any) if (!String.IsNullOrEmpty(mapping.Functions)) { try { LogInfo(LogStrings.ProcessingMappingFunctions, LogStrings.Heading_MappingWebParts); functionProcessor.ProcessMappingFunctions(ref webPartData, webPart, mapping); } catch (Exception ex) { // NotAvailableAtTargetException is used to "skip" a web part since it's not valid for the target site collection (only applies to cross site collection transfers) if (ex.InnerException is NotAvailableAtTargetException) { LogError(LogStrings.Error_NotValidForTargetSiteCollection, LogStrings.Heading_MappingWebParts, ex, true); continue; } LogError($"{LogStrings.Error_AnErrorOccurredFunctions} - {ex.Message}", LogStrings.Heading_MappingWebParts, ex); throw; } } } // Use the mapping data => make one list of Text and WebParts to allow for correct ordering LogDebug("Combining mapping data", LogStrings.Heading_MappingWebParts); combinedMappinglist = new List <CombinedMapping>(); if (mapping.ClientSideText != null) { foreach (var map in mapping.ClientSideText.OrderBy(p => p.Order)) { if (!Int32.TryParse(map.Order, out Int32 mapOrder)) { mapOrder = 0; } combinedMappinglist.Add(new CombinedMapping { ClientSideText = map, ClientSideWebPart = null, Order = mapOrder }); } } if (mapping.ClientSideWebPart != null) { foreach (var map in mapping.ClientSideWebPart.OrderBy(p => p.Order)) { if (!Int32.TryParse(map.Order, out Int32 mapOrder)) { mapOrder = 0; } combinedMappinglist.Add(new CombinedMapping { ClientSideText = null, ClientSideWebPart = map, Order = mapOrder }); } } // Get the order of the last inserted control in this column int order = LastColumnOrder(webPart.Row - 1, webPart.Column - 1); // Interate the controls for this mapping using their order foreach (var map in combinedMappinglist.OrderBy(p => p.Order)) { order++; if (map.ClientSideText != null) { // Insert a Text control //PnP.Framework.Pages.ClientSideText text = new PnP.Framework.Pages.ClientSideText() //{ // Text = TokenParser.ReplaceTokens(map.ClientSideText.Text, webPart) //}; var text = page.NewTextPart(); text.Text = TokenParser.ReplaceTokens(map.ClientSideText.Text, webPart); page.AddControl(text, page.Sections[webPart.Row - 1].Columns[webPart.Column - 1], order); LogInfo(LogStrings.AddedClientSideTextWebPart, LogStrings.Heading_AddingWebPartsToPage); } else if (map.ClientSideWebPart != null) { // Insert a web part //ClientSideComponent baseControl = null; PnPCore.IPageComponent baseControl = null; if (map.ClientSideWebPart.Type == ClientSideWebPartType.Custom) { // Parse the control ID to support generic web part placement scenarios map.ClientSideWebPart.ControlId = TokenParser.ReplaceTokens(map.ClientSideWebPart.ControlId, webPart); // Check if this web part belongs to the list of "usable" web parts for this site baseControl = componentsToAdd.FirstOrDefault(p => p.Id.Equals($"{{{map.ClientSideWebPart.ControlId}}}", StringComparison.InvariantCultureIgnoreCase)); LogInfo(LogStrings.UsingCustomModernWebPart, LogStrings.Heading_AddingWebPartsToPage); } else { string webPartName = ""; switch (map.ClientSideWebPart.Type) { case ClientSideWebPartType.List: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.List); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.List); break; } case ClientSideWebPartType.Image: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Image); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Image); break; } case ClientSideWebPartType.ContentRollup: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.ContentRollup); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.ContentRollup); break; } case ClientSideWebPartType.BingMap: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.BingMap); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.BingMap); break; } case ClientSideWebPartType.ContentEmbed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.ContentEmbed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.ContentEmbed); break; } case ClientSideWebPartType.DocumentEmbed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.DocumentEmbed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.DocumentEmbed); break; } case ClientSideWebPartType.ImageGallery: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.ImageGallery); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.ImageGallery); break; } case ClientSideWebPartType.LinkPreview: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.LinkPreview); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.LinkPreview); break; } case ClientSideWebPartType.NewsFeed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.NewsFeed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.NewsFeed); break; } case ClientSideWebPartType.NewsReel: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.NewsReel); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.NewsReel); break; } case ClientSideWebPartType.News: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.News); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.News); break; } case ClientSideWebPartType.PowerBIReportEmbed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.PowerBIReportEmbed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.PowerBIReportEmbed); break; } case ClientSideWebPartType.QuickChart: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.QuickChart); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.QuickChart); break; } case ClientSideWebPartType.SiteActivity: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.SiteActivity); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.SiteActivity); break; } case ClientSideWebPartType.VideoEmbed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.VideoEmbed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.VideoEmbed); break; } case ClientSideWebPartType.YammerEmbed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.YammerEmbed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.YammerEmbed); break; } case ClientSideWebPartType.Events: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Events); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Events); break; } case ClientSideWebPartType.GroupCalendar: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.GroupCalendar); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.GroupCalendar); break; } case ClientSideWebPartType.Hero: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Hero); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Hero); break; } case ClientSideWebPartType.PageTitle: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.PageTitle); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.PageTitle); break; } case ClientSideWebPartType.People: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.People); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.People); break; } case ClientSideWebPartType.QuickLinks: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.QuickLinks); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.QuickLinks); break; } case ClientSideWebPartType.Divider: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Divider); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Divider); break; } case ClientSideWebPartType.MicrosoftForms: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.MicrosoftForms); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.MicrosoftForms); break; } case ClientSideWebPartType.Spacer: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Spacer); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Spacer); break; } case ClientSideWebPartType.ClientWebPart: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.ClientWebPart); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.ClientWebPart); break; } case ClientSideWebPartType.PowerApps: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.PowerApps); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.PowerApps); break; } case ClientSideWebPartType.CodeSnippet: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.CodeSnippet); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.CodeSnippet); break; } case ClientSideWebPartType.PageFields: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.PageFields); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.PageFields); break; } case ClientSideWebPartType.Weather: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Weather); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Weather); break; } case ClientSideWebPartType.YouTube: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.YouTube); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.YouTube); break; } case ClientSideWebPartType.MyDocuments: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.MyDocuments); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.MyDocuments); break; } case ClientSideWebPartType.YammerFullFeed: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.YammerFullFeed); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.YammerFullFeed); break; } case ClientSideWebPartType.CountDown: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.CountDown); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.CountDown); break; } case ClientSideWebPartType.ListProperties: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.ListProperties); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.ListProperties); break; } case ClientSideWebPartType.MarkDown: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.MarkDown); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.MarkDown); break; } case ClientSideWebPartType.Planner: { //webPartName = ClientSidePage.ClientSideWebPartEnumToName(DefaultClientSideWebParts.Planner); webPartName = page.DefaultWebPartToWebPartId(PnPCore.DefaultWebPart.Planner); break; } default: { break; } } // SharePoint add-ins can be added on client side pages...all add-ins are added via the client web part, so we need additional logic to find the one we need if (map.ClientSideWebPart.Type == ClientSideWebPartType.ClientWebPart) { var addinComponents = componentsToAdd.Where(p => p.Name.Equals(webPartName, StringComparison.InvariantCultureIgnoreCase)); foreach (var addin in addinComponents) { // Find the right add-in web part via title matching...maybe not bullet proof but did find anything better for now JObject wpJObject = JObject.Parse(addin.Manifest); // As there can be multiple classic web parts (via provider hosted add ins or SharePoint hosted add ins) we're looping to find the first one with a matching title foreach (var addinEntry in wpJObject["preconfiguredEntries"]) { if (addinEntry["title"]["default"].Value <string>() == webPart.Title) { baseControl = addin; var jsonProperties = addinEntry; // Fill custom web part properties in this json. Custom properties are listed as child elements under clientWebPartProperties, // replace their "default" value with the value we got from the web part's properties jsonProperties = PopulateAddInProperties(jsonProperties, webPart); // Override the JSON data we read from the model as this is fully dynamic due to the nature of the add-in client part map.ClientSideWebPart.JsonControlData = jsonProperties.ToString(Newtonsoft.Json.Formatting.None); LogInfo($"{LogStrings.ContentUsingAddinWebPart} '{baseControl.Name}' ", LogStrings.Heading_AddingWebPartsToPage); break; } } } } else { baseControl = componentsToAdd.FirstOrDefault(p => p.Name.Equals(webPartName, StringComparison.InvariantCultureIgnoreCase)); LogInfo($"{LogStrings.ContentUsing} '{ map.ClientSideWebPart.Type.ToString() }' {LogStrings.ContentModernWebPart}", LogStrings.Heading_AddingWebPartsToPage); } } // If we found the web part as a possible candidate to use then add it if (baseControl != null) { var jsonDecoded = WebUtility.HtmlDecode(TokenParser.ReplaceTokens(map.ClientSideWebPart.JsonControlData, webPart)); //PnP.Framework.Pages.ClientSideWebPart myWebPart = new PnP.Framework.Pages.ClientSideWebPart(baseControl) //{ // Order = map.Order, // PropertiesJson = jsonDecoded //}; var myWebPart = page.NewWebPart(baseControl); myWebPart.Order = map.Order; myWebPart.PropertiesJson = jsonDecoded; page.AddControl(myWebPart, page.Sections[webPart.Row - 1].Columns[webPart.Column - 1], order); LogInfo($"{LogStrings.ContentAdded} '{ myWebPart.Title }' {LogStrings.ContentClientToTargetPage}", LogStrings.Heading_AddingWebPartsToPage); } else { LogWarning(LogStrings.ContentWarnModernNotFound, LogStrings.Heading_AddingWebPartsToPage); } } } } LogInfo(LogStrings.ContentTransformationComplete, LogStrings.Heading_ContentTransform); }