From 15558cd37493a8dc3a1fc1d05a06e10855b3e5ac Mon Sep 17 00:00:00 2001 From: Enrico Cimitan Date: Mon, 10 Feb 2025 13:58:49 +0100 Subject: [PATCH 1/2] Update code --- .gitignore | 1 + .../PBIEmbedGenerator.csproj | 29 +- .../PBIEmbedGenerator/Program.cs | 551 +++++------------- .../Properties/Resources.Designer.cs | 113 ++++ .../Properties/Resources.resx | 136 +++++ .../Resources/ObsoleteProperties.txt | 3 + .../Resources/PermissionSetTemplate.txt | 8 + .../Resources/ReportPageTemplate.txt | 51 ++ .../Resources/RoleCenterActionTemplate.txt | 7 + .../Resources/RoleCenterExtensionTemplate.txt | 19 + .../PBIPayloadGenerator/ActionDefinition.cs | 7 +- .../PBIPayloadGenerator/PBIPageDefinition.cs | 28 +- .../PayloadGenerator.csproj | 10 +- .../PBIPayloadGenerator/PermSetDefinition.cs | 8 +- .../PBIPayloadGenerator/Program.cs | 187 +++--- .../RCExtensionDefinition.cs | 20 +- 16 files changed, 617 insertions(+), 561 deletions(-) create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.Designer.cs create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.resx create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ObsoleteProperties.txt create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/PermissionSetTemplate.txt create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ReportPageTemplate.txt create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterActionTemplate.txt create mode 100644 samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterExtensionTemplate.txt diff --git a/.gitignore b/.gitignore index 342c97e2..3deb3ed6 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +.pkgrefgen/ # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj index 1f6d4ca6..3960a212 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj @@ -1,16 +1,39 @@ - + Exe - net7.0 + net8.0 - + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs index 5d1cf7ce..c82000cf 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs @@ -1,9 +1,9 @@ -using System; -using System.Xml; -using System.Text; +using PBIEmbedGenerator.Properties; +using System; +using System.CommandLine; using System.IO; -using Mono.Options; -using System.Collections.Generic; +using System.Text; +using System.Xml; namespace APIQueryGenerator { @@ -11,43 +11,38 @@ class Program { static void Main(string[] args) { - // http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html - bool show_help = false; - string inputfile = ""; - string outputdir = ""; - Version version = new Version(); - - var p = new OptionSet() { - { "h|help", "show this message and exit", v => show_help = v != null }, - { "i|inputfile=", "input xml file (required)", v => inputfile = v }, - { "o|outputdir=", "output directory (if not specified, then input file name will be used)", v => outputdir = v }, - { "v|version=", "target Business Central version", v => version = new Version(v) } + var inputFileOption = new Option("--inputfile", "The XML payload input file") + { + IsRequired = true }; - - List extra; - try + inputFileOption.AddAlias("--i"); + var outputDirOption = new Option("--outputdir", "The output directory where the AL files will be generated") { - extra = p.Parse(args); - } - catch (OptionException e) + IsRequired = true + }; + outputDirOption.AddAlias("--o"); + + var rootCommand = new RootCommand("Power BI content - AL generator"); + rootCommand.AddOption(inputFileOption); + rootCommand.AddOption(outputDirOption); + rootCommand.SetHandler((inputFile, outputDir) => { - Console.WriteLine(e.Message); - Console.WriteLine("Try using --help' for more information."); - Environment.Exit(0); - } + Run(inputFile.FullName, outputDir.FullName); + }, inputFileOption, outputDirOption); - if (show_help) + try { - ShowHelp(p); - Environment.Exit(0); + rootCommand.InvokeAsync(args); } - - if (inputfile.Equals("")) + catch (Exception ex) { - ShowHelp(p); - Environment.Exit(0); + Console.WriteLine(ex.Message); + Environment.Exit(-1); } + } + static void Run(string inputfile, string outputdir) + { Console.WriteLine("PBI embed page AL code generator"); Console.WriteLine("------------------------"); @@ -60,7 +55,7 @@ static void Main(string[] args) catch (Exception e) { Console.WriteLine("Could not read input file as a xml file."); - Environment.Exit(0); + Environment.Exit(-1); } @@ -90,7 +85,7 @@ static void Main(string[] args) Console.WriteLine("Found {0} pages", pages.SelectNodes("page").Count.ToString()); foreach (XmlNode page in pages.SelectNodes("page")) { - var content = GeneratePBIEmbedPageCode(alNamespace, page, version); + var content = GeneratePBIEmbedPageCode(alNamespace, page); var filename = page.Attributes["filename"].Value; SaveFile(outputdir, filename, content); Console.WriteLine(filename); @@ -121,381 +116,151 @@ static void Main(string[] args) } - private static void indents(StringBuilder sb, int indentLevel) - { - var indent = " "; - - for (int i = 0; i < indentLevel; i++) - { - sb.Append(indent); - } - } - - private static void indentAppendLine(StringBuilder sb, int indentLevel, string s) - { - indents(sb, indentLevel); - sb.AppendLine(s); - } - public static string GeneratePBIRCExtensionCode(string alNamespace, XmlNode rcExt) { - StringBuilder sb = new StringBuilder(); - - /* - pageextension 50100 BusinessManagerRoleCenterExt extends "Business Manager Role Center" - */ - - sb.AppendLine("// Auto-generated al file for PBI role centre extension " + rcExt.Attributes["id"].Value); - sb.AppendLine("// "); - sb.AppendLine("// Adding actions for the following AL PBI pages:"); + StringBuilder actionssb = new StringBuilder(); foreach (XmlNode action in rcExt.SelectNodes("action")) { - sb.AppendLine("// * " + action.Attributes["pbipagename"].Value ); + GeneratePBIRCExtensionActionCode(action, actionssb); } - sb.AppendLine(""); - - sb.AppendLine("namespace " + alNamespace); - sb.AppendLine(""); - - sb.AppendLine("pageextension " + rcExt.Attributes["id"].Value + " \"" + rcExt.Attributes["name"].Value + "\" extends \"" + rcExt.Attributes["extends"].Value + "\""); - sb.AppendLine("{"); - - indents(sb, 1); - sb.AppendLine("actions"); - - indents(sb, 1); - sb.AppendLine("{"); - - indents(sb, 2); - sb.AppendLine(rcExt.Attributes["where"].Value); - - indents(sb, 2); - sb.AppendLine("{"); - - indents(sb, 3); - sb.AppendLine("group(\"PBIReports\")"); - indents(sb, 3); - sb.AppendLine("{"); - - indents(sb, 4); - sb.AppendLine("Caption = 'Power BI Reports';"); + StringBuilder sb = new StringBuilder(); - indents(sb, 4); - sb.AppendLine("Image = PowerBI;"); + sb.AppendFormat(Encoding.UTF8.GetString(Resources.RoleCenterExtensionTemplate), + alNamespace, // 0 + rcExt.Attributes["rolecenternamespace"].Value, // 1 + rcExt.Attributes["id"].Value, // 2 + EscapeALTextString(rcExt.Attributes["name"].Value), // 3 + EscapeALTextString(rcExt.Attributes["extends"].Value), // 4 + rcExt.Attributes["where"].Value, // 5 + rcExt.Attributes["image"].Value, // 6 + rcExt.Attributes["tooltip"].Value, // 7 + actionssb.ToString() // 8 + ); - indents(sb, 4); - sb.AppendLine("ToolTip = '" + rcExt.Attributes["tooltip"].Value + "';"); + return sb.ToString(); + } - foreach (XmlNode action in rcExt.SelectNodes("action")) + public static void GeneratePBIRCExtensionActionCode(XmlNode action, StringBuilder sb) + { + if (action.Attributes["obsolete"].Value.Length > 0) { - var content = GeneratePBIRCExtensionActionCode(action, sb); + sb.AppendLine($"#if not CLEAN{action.Attributes["obsolete"].Value}"); + } + StringBuilder additionalActionProperties = new StringBuilder(); + if (!string.IsNullOrEmpty(action.Attributes["tooltip"].Value)){ + additionalActionProperties.AppendLine($" Tooltip = '{EscapeALTextString(action.Attributes["tooltip"].Value)}';"); + } + if (action.Attributes["obsolete"].Value.Length > 0) + { + var indentationInAction = " "; + additionalActionProperties.AppendFormat(Encoding.UTF8.GetString(Resources.ObsoletePropertiesTemplate), + indentationInAction, + EscapeALTextString(action.Attributes["obsolete"].Value) + ); + additionalActionProperties.AppendLine(); + additionalActionProperties.AppendLine(indentationInAction + "Visible = false;"); + } + sb.AppendFormat(Encoding.UTF8.GetString(Resources.RoleCenterActionTemplate), + action.Attributes["name"].Value, // 0 + EscapeALTextString(action.Attributes["caption"].Value), // 1 + action.Attributes["pbipagename"].Value, // 2 + additionalActionProperties // 3 + ); + if (action.Attributes["obsolete"].Value.Length > 0) + { + sb.AppendLine("#endif"); } - - indents(sb, 3); - sb.AppendLine("}"); - - indents(sb, 2); - sb.AppendLine("}"); - - indents(sb, 1); - sb.AppendLine("}"); - - sb.AppendLine("}"); - - return sb.ToString(); } - public static string GeneratePBIRCExtensionActionCode(XmlNode action, StringBuilder sb) + public static string GeneratePBIEmbedPageCode(string alNamespace, XmlNode query) { - //action(PBIFinancialOverview) - //{ - // ApplicationArea = Basic, Suite; - // Caption = 'Financial Overview'; - // Image = "PowerBI"; - // RunObject = page PBIFinancialOverview; - // ToolTip = 'Open a Power BI report that shows your company''s assets, liabilities, and equity.'; - //} - - sb.AppendLine(""); - - indents(sb, 4); - sb.AppendLine("action(" + action.Attributes["name"].Value + ")"); - - indents(sb, 4); - sb.AppendLine("{"); - - indents(sb, 5); - sb.AppendLine("ApplicationArea = Basic, Suite;"); - - indents(sb, 5); - sb.AppendLine("Caption = '" + action.Attributes["caption"].Value + "';"); - - indents(sb, 5); - sb.AppendLine("Image = \"PowerBI\";"); - - indents(sb, 5); - sb.AppendLine("RunObject = page \"" + action.Attributes["pbipagename"].Value + "\";"); - - indents(sb, 5); - sb.AppendLine("Tooltip = '" + action.Attributes["tooltip"].Value + "';"); - - indents(sb, 4); - sb.AppendLine("}"); + StringBuilder sb = new StringBuilder(); + StringBuilder additionalProperties = new StringBuilder(); + if (query.Attributes["obsolete"].Value.Length > 0) + { + var indentationInAction = " "; + sb.AppendLine($"#if not CLEAN{query.Attributes["obsolete"].Value}"); + additionalProperties.AppendFormat(Encoding.UTF8.GetString(Resources.ObsoletePropertiesTemplate), + indentationInAction, + EscapeALTextString(query.Attributes["obsolete"].Value) + ); + } + var applicationArea = query.Attributes["applicationArea"].Value.Length > 0 ? query.Attributes["applicationArea"].Value : "All" ; + + sb.AppendFormat(Encoding.UTF8.GetString(Resources.ReportPageTemplate), + alNamespace, // 0 + query.Attributes["id"].Value, // 1 + query.Attributes["name"].Value, // 2 + EscapeALTextString(query.Attributes["caption"].Value), // 3 + EscapeALTextString(query.Attributes["aboutTitle"].Value), // 4 + EscapeALTextString(query.Attributes["aboutText"].Value), // 5 + query.Attributes["PBIReportPage"].Value, // 6 + query.Attributes["PBIReportIdFieldName"].Value, // 7 + additionalProperties, // 8 + applicationArea // 9 + ); + if (query.Attributes["obsolete"].Value.Length > 0) + { + sb.AppendLine("#endif"); + } return sb.ToString(); } - - public static string GeneratePBIEmbedPageCode(string alNamespace, XmlNode query, Version version) + public static string GeneratePBIEmbedPagePerm(string alNamespace, XmlNode permSet, XmlNode pages) { - StringBuilder sb = new StringBuilder(); - string context = query.Attributes["id"].Value + "-" + query.Attributes["name"].Value; - - /* - // Auto-generated al file for PBI embed page - // - // Adding a PBI embed page for this PBI content: - // PBI ReportId = '' - // PBI ReportName = '' - - namespace Microsoft.PowerBIApps - - page "" + StringBuilder pageStringBuilder = new StringBuilder(); + foreach (XmlNode page in pages.SelectNodes("page")) { - UsageCategory = ReportsAndAnalysis; - Caption = ''; - AboutTitle = ''; - AboutText = ''; - - layout + if (page.Attributes["name"].Value == pages.LastChild.Attributes["name"].Value) { - area(Content) + pageStringBuilder.AppendLine(" page \"" + page.Attributes["name"].Value + "\" = X;"); + } + else + { + if (page.NextSibling.Attributes["obsolete"].Value.Length > 0 && page.NextSibling.Attributes["name"].Value == pages.LastChild.Attributes["name"].Value) { - part(EmbeddedReport; "Power BI Embedded Report Part") - { - Caption = 'Financial Overview'; - SubPageView = where(Context = const('-')); - ApplicationArea = All; - } + pageStringBuilder.AppendLine($"#if not CLEAN{page.NextSibling.Attributes["obsolete"].Value}"); + pageStringBuilder.AppendLine(" page \"" + page.Attributes["name"].Value + "\" = X,"); + pageStringBuilder.AppendLine("#pragma warning disable AL0432"); + pageStringBuilder.AppendLine(" page \"" + page.NextSibling.Attributes["name"].Value + "\" = X;"); + pageStringBuilder.AppendLine("#pragma warning restore AL0432"); + pageStringBuilder.AppendLine("#else"); + pageStringBuilder.AppendLine(" page \"" + page.Attributes["name"].Value + "\" = X;"); + pageStringBuilder.AppendLine("#endif"); + break; } - } - */ - - sb.AppendLine("// Auto-generated al file for PBI embed page " + query.Attributes["id"].Value); - sb.AppendLine("// "); - sb.AppendLine("// Adding a PBI embed page for this PBI content:"); - sb.AppendLine("// PBI ReportId = '" + query.Attributes["PBIReportId"].Value); - sb.AppendLine("// PBI ReportName = '" + query.Attributes["PBIReportName"].Value); - sb.AppendLine(""); - - sb.AppendLine("namespace " + alNamespace); - sb.AppendLine(""); - - sb.AppendLine("page " + query.Attributes["id"].Value + " \"" + query.Attributes["name"].Value + "\""); - sb.AppendLine("{"); - - indentAppendLine(sb, 1, "UsageCategory = ReportsAndAnalysis;"); - indentAppendLine(sb, 1, "Caption = '" + query.Attributes["caption"].Value + "';"); - indentAppendLine(sb, 1, "AboutTitle = '" + query.Attributes["aboutTitle"].Value + "'; "); - indentAppendLine(sb, 1, "AboutText = '" + query.Attributes["aboutText"].Value + "'; "); - sb.AppendLine(""); - - indentAppendLine(sb, 1, "layout"); - indentAppendLine(sb, 1, "{"); - - indentAppendLine(sb, 2, "area(Content)"); - indentAppendLine(sb, 2, "{"); - - indentAppendLine(sb, 3, "part(EmbeddedReport; \"Power BI Embedded Report Part\")"); - indentAppendLine(sb, 3, "{"); - - indentAppendLine(sb, 4, "ApplicationArea = All;"); - indentAppendLine(sb, 4, "Caption = '" + query.Attributes["caption"].Value + "';"); - indentAppendLine(sb, 4, "SubPageView = where(Context = const ('" + context + "'));"); - - indentAppendLine(sb, 3, "}"); - - indentAppendLine(sb, 2, "}"); - indentAppendLine(sb, 1, "}"); - sb.AppendLine(""); - - /* - trigger OnOpenPage() - var - PowerBIDisplayedElement: Record "Power BI Displayed Element"; - PowerBIServiceMgt: Codeunit "Power BI Service Mgt."; - begin - EnsureUserAcceptedPowerBITerms(); - - // Cleanup previously added reports for this context - PowerBIDisplayedElement.SetRange(Context, vContext); - PowerBIDisplayedElement.DeleteAll(); - PowerBIDisplayedElement.SetRange(Context); - - // Add the report - PowerBIServiceMgt.AddReportForContext(vReportId, vContext); - - // Customize page and other settings - PowerBIDisplayedElement.Get(UserSecurityId(), vContext, PowerBIDisplayedElement.MakeReportKey(vReportId), - PowerBIDisplayedElement.ElementType::Report); - PowerBIDisplayedElement.ReportPage := vReportPage; - PowerBIDisplayedElement.ShowPanesInExpandedMode := true; - PowerBIDisplayedElement.ShowPanesInNormalMode := true; - PowerBIDisplayedElement.Modify(); - - CurrPage.EmbeddedReport.Page.SetFullPageMode(true); - end; - */ - indentAppendLine(sb, 1, "trigger OnOpenPage()"); - indentAppendLine(sb, 1, "var"); - - indentAppendLine(sb, 2, "PowerBIDisplayedElement: Record \"Power BI Displayed Element\";"); - indentAppendLine(sb, 2, "PowerBIServiceMgt: Codeunit \"Power BI Service Mgt.\";"); - - indentAppendLine(sb, 1, "begin"); - - indentAppendLine(sb, 2, "EnsureUserAcceptedPowerBITerms();"); - sb.AppendLine(""); - indentAppendLine(sb, 2, "// Cleanup previously added reports for this context"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.SetRange(Context, vContext);"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.DeleteAll();"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.SetRange(Context);"); - sb.AppendLine(""); - indentAppendLine(sb, 2, "// Add the report"); - indentAppendLine(sb, 2, "PowerBIServiceMgt.AddReportForContext(vReportId, vContext);"); - sb.AppendLine(""); - indentAppendLine(sb, 2, "// Customize page and other settings"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.Get(UserSecurityId(), vContext, PowerBIDisplayedElement.MakeReportKey(vReportId), PowerBIDisplayedElement.ElementType::Report);"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.ReportPage := vReportPage;"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.ShowPanesInExpandedMode := true;"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.ShowPanesInNormalMode := true;"); - indentAppendLine(sb, 2, "PowerBIDisplayedElement.Modify();"); - sb.AppendLine(""); - - if (version == new Version() | version >= new Version("24.2")) - { - indentAppendLine(sb, 2, "CurrPage.EmbeddedReport.Page.SetFullPageMode(true);"); + if (page.Attributes["obsolete"].Value.Length > 0) + { + pageStringBuilder.AppendLine($"#if not CLEAN{page.Attributes["obsolete"].Value}"); + pageStringBuilder.AppendLine("#pragma warning disable AL0432"); + } + pageStringBuilder.AppendLine(" page \"" + page.Attributes["name"].Value + "\" = X,"); + if (page.Attributes["obsolete"].Value.Length > 0) + { + pageStringBuilder.AppendLine("#pragma warning restore AL0432"); + pageStringBuilder.AppendLine("#endif"); + } + } } - indentAppendLine(sb, 1, "end;"); - sb.AppendLine(""); - - /* - local procedure EnsureUserAcceptedPowerBITerms() - var - PowerBIContextSettings: Record "Power BI Context Settings"; - PowerBIEmbedSetupWizard: Page "Power BI Embed Setup Wizard"; - begin - PowerBIContextSettings.SetRange(UserSID, UserSecurityId()); - if PowerBIContextSettings.IsEmpty() then begin - PowerBIEmbedSetupWizard.SetContext(vContext); - if PowerBIEmbedSetupWizard.RunModal() <> Action::OK then; - - if PowerBIContextSettings.IsEmpty() then - Error(PowerBiNotSetupErr); - end; - - PowerBIContextSettings.CreateOrReadForCurrentUser(vContext); - if not PowerBIContextSettings.LockToSelectedElement then begin - PowerBIContextSettings.LockToSelectedElement := true; - PowerBIContextSettings.Modify(); - end; - end; - */ - indentAppendLine(sb, 1, "local procedure EnsureUserAcceptedPowerBITerms()"); - indentAppendLine(sb, 1, "var"); - - indentAppendLine(sb, 2, "PowerBIContextSettings: Record \"Power BI Context Settings\";"); - indentAppendLine(sb, 2, "PowerBIEmbedSetupWizard: Page \"Power BI Embed Setup Wizard\";"); - - indentAppendLine(sb, 1, "begin"); - - indentAppendLine(sb, 2, "PowerBIContextSettings.SetRange(UserSID, UserSecurityId());"); - indentAppendLine(sb, 2, "if PowerBIContextSettings.IsEmpty() then begin"); - - indentAppendLine(sb, 3, "PowerBIEmbedSetupWizard.SetContext(vContext);"); - indentAppendLine(sb, 3, "if PowerBIEmbedSetupWizard.RunModal() <> Action::OK then;"); - sb.AppendLine(""); - indentAppendLine(sb, 3, "if PowerBIContextSettings.IsEmpty() then"); - - indentAppendLine(sb, 4, "Error(PowerBiNotSetupErr);"); - - indentAppendLine(sb, 2, "end;"); - sb.AppendLine(""); - indentAppendLine(sb, 2, "PowerBIContextSettings.CreateOrReadForCurrentUser(vContext);"); - indentAppendLine(sb, 2, "if not PowerBIContextSettings.LockToSelectedElement then begin"); - - indentAppendLine(sb, 3, "PowerBIContextSettings.LockToSelectedElement := true;"); - indentAppendLine(sb, 3, "PowerBIContextSettings.Modify();"); - - indentAppendLine(sb, 2, "end;"); - - indentAppendLine(sb, 1, "end;"); - sb.AppendLine(""); + StringBuilder sb = new StringBuilder(); - /* - var - PowerBiNotSetupErr: Label 'Power BI is not set up. You need to set up Power BI in order to see this report.'; - vReportId: Label '', Locked = true; - vReportPage: Label '', Locked = true; - vContext: Label '-', MaxLength = 30, Locked = true, Comment = 'IMPORTANT: keep it unique across pages. Also, make sure this value is the same used in the SubPageView above.'; - */ - indentAppendLine(sb, 1, "var"); - - indentAppendLine(sb, 2, "PowerBiNotSetupErr: Label 'Power BI is not set up. You need to set up Power BI in order to see this report.';"); - indentAppendLine(sb, 2, "vReportId: Label '" + query.Attributes["PBIReportId"].Value + "', Locked = true;"); - indentAppendLine(sb, 2, "vReportPage: Label '" + query.Attributes["PBIReportPage"].Value + "', Locked = true;"); - indentAppendLine(sb, 2, "vContext: Label '" + context + "', MaxLength = 30, Locked = true, Comment = 'IMPORTANT: keep it unique across pages. Also, make sure this value is the same used in the SubPageView above.';"); - - sb.AppendLine(""); - sb.AppendLine("}"); + sb.AppendFormat(Encoding.UTF8.GetString(Resources.PermissionSetTemplate), + alNamespace, // 0 + permSet.Attributes["id"].Value, // 1 + permSet.Attributes["name"].Value, // 2 + pageStringBuilder.ToString() // 3 + ); return sb.ToString(); } - public static string GeneratePBIEmbedPagePerm(string alNamespace, XmlNode permSet, XmlNode pages) + public static string EscapeALTextString(string s) { - StringBuilder sb = new StringBuilder(); - - /* - // Auto-generated al file for PBI permissions 50120 - - namespace Microsoft.PowerBIApps - - permissionset 50120 "Power BI Finance App - Objects" - { - Access = Internal; - Assignable = false; - Permissions = - page "PBIFinancialOverview" = X, - page "PBIIncomeStatementbyMonth" = X, - page "PBIBalanceSheetbyMonth" = X, - page "PBIBudgetComparison" = X, - page "PBILiquidityKPIs" = X, - page "PBIProfitability" = X, - } - */ - - indentAppendLine(sb, 0, "// Auto-generated al file for PBI permissions " + permSet.Attributes["id"].Value); - indentAppendLine(sb, 0, ""); - indentAppendLine(sb, 0, "namespace " + alNamespace); - indentAppendLine(sb, 0, ""); - indentAppendLine(sb, 0, "permissionset " + permSet.Attributes["id"].Value + " \"" + permSet.Attributes["name"].Value + "\""); - indentAppendLine(sb, 0, "{"); - indentAppendLine(sb, 1, "Access = Internal;"); - indentAppendLine(sb, 1, "Assignable = false;"); - indentAppendLine(sb, 1, "Permissions ="); - - foreach (XmlNode page in pages.SelectNodes("page")) - { - indentAppendLine(sb, 2, "page \"" + page.Attributes["name"].Value + "\" = X,"); - } - - indentAppendLine(sb, 0, "}"); - - return sb.ToString(); + return s.Replace("'", "''"); } // https://epsicodecom.wordpress.com/2019/08/12/tutorial-generate-seperate-files-from-a-t4-template/ @@ -510,35 +275,5 @@ public static void SaveFile(string folder, string fileName, string content) } } } - - static void ShowHelp(OptionSet p) - { - Console.WriteLine("Usage: APIQueryGenerator [OPTIONS]+"); - Console.WriteLine(); - Console.WriteLine("Options:"); - p.WriteOptionDescriptions(Console.Out); - - Console.WriteLine("-------------------"); - var exampleXML = """ - - - - - - - - - - - - - -"""; - - Console.WriteLine("Example input file"); - Console.WriteLine(exampleXML); - Console.WriteLine("-------------------"); - } - } } diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.Designer.cs b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.Designer.cs new file mode 100644 index 00000000..6a95b471 --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.Designer.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PBIEmbedGenerator.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PBIEmbedGenerator.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ObsoletePropertiesTemplate { + get { + object obj = ResourceManager.GetObject("ObsoletePropertiesTemplate", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] PermissionSetTemplate { + get { + object obj = ResourceManager.GetObject("PermissionSetTemplate", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ReportPageTemplate { + get { + object obj = ResourceManager.GetObject("ReportPageTemplate", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] RoleCenterActionTemplate { + get { + object obj = ResourceManager.GetObject("RoleCenterActionTemplate", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] RoleCenterExtensionTemplate { + get { + object obj = ResourceManager.GetObject("RoleCenterExtensionTemplate", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.resx b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.resx new file mode 100644 index 00000000..5cb0b27a --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources.resx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\PermissionSetTemplate.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\ReportPageTemplate.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\RoleCenterActionTemplate.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\RoleCenterExtensionTemplate.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\ObsoleteProperties.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ObsoleteProperties.txt b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ObsoleteProperties.txt new file mode 100644 index 00000000..7e4f6347 --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ObsoleteProperties.txt @@ -0,0 +1,3 @@ +{0}ObsoleteState = Pending; +{0}ObsoleteReason = 'The Power BI report has been changed/removed and this is no longer required.'; +{0}ObsoleteTag = '{1}.0'; \ No newline at end of file diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/PermissionSetTemplate.txt b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/PermissionSetTemplate.txt new file mode 100644 index 00000000..bc5c1a9d --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/PermissionSetTemplate.txt @@ -0,0 +1,8 @@ +namespace {0}; + +permissionset {1} "{2}" +{{ + Access = Internal; + Assignable = false; + Permissions = +{3}}} diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ReportPageTemplate.txt b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ReportPageTemplate.txt new file mode 100644 index 00000000..8a0183e6 --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/ReportPageTemplate.txt @@ -0,0 +1,51 @@ +namespace {0}; + +using System.Integration.PowerBI; + +page {1} "{2}" +{{ + UsageCategory = ReportsAndAnalysis; + ApplicationArea = {9}; +#pragma warning disable AS0035 // Changed from Card to UserControlHost + PageType = UserControlHost; +#pragma warning restore AS0035 + Caption = '{3}'; + AboutTitle = '{4}'; + AboutText = '{5}'; +{8} + layout + {{ + area(Content) + {{ + usercontrol(PowerBIAddin; PowerBIManagement) + {{ + ApplicationArea = All; + + trigger ControlAddInReady() + begin + SetupHelper.InitializeEmbeddedAddin(CurrPage.PowerBIAddin, ReportId, ReportPageLbl); + end; + + trigger ErrorOccurred(Operation: Text; ErrorText: Text) + begin + SetupHelper.ShowPowerBIErrorNotification(Operation, ErrorText); + end; + }} + }} + }} + + var + SetupHelper: Codeunit "Setup Helper"; + ReportId: Guid; +#pragma warning disable AA0240 + ReportPageLbl: Label '{6}', Locked = true; +#pragma warning restore AA0240 + + trigger OnOpenPage() + var + PowerBIReportsSetup: Record "PowerBI Reports Setup"; + begin + SetupHelper.EnsureUserAcceptedPowerBITerms(); + ReportId := SetupHelper.GetReportIdAndEnsureSetup(CurrPage.Caption(), PowerBIReportsSetup.FieldNo("{7}")); + end; +}} diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterActionTemplate.txt b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterActionTemplate.txt new file mode 100644 index 00000000..6034684d --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterActionTemplate.txt @@ -0,0 +1,7 @@ + action("{0}") + {{ + ApplicationArea = Basic, Suite; + Caption = '{1}'; + Image = "PowerBI"; + RunObject = page "{2}"; +{3} }} diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterExtensionTemplate.txt b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterExtensionTemplate.txt new file mode 100644 index 00000000..05ac1252 --- /dev/null +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Properties/Resources/RoleCenterExtensionTemplate.txt @@ -0,0 +1,19 @@ +namespace {0}; + +using {1}; + +pageextension {2} "{3}" extends "{4}" +{{ + actions + {{ + {5} + {{ + group("PBI Reports") + {{ + Caption = 'Power BI Reports'; + Image = {6}; + ToolTip = '{7}'; +{8} }} + }} + }} +}} diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/ActionDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/ActionDefinition.cs index 4b31d542..f13803e3 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/ActionDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/ActionDefinition.cs @@ -9,14 +9,16 @@ internal class ActionDefinition string caption { get; set; } string pbipagename { get; set; } string tooltip { get; set; } + string obsolete { get; set; } - public ActionDefinition(string rcExtenionName, string name, string caption, string pbipagename, string tooltip) + public ActionDefinition(string rcExtenionName, string name, string caption, string pbipagename, string tooltip, string obsolete) { this.rcExtensionName = rcExtenionName; this.name = name; this.caption = caption; this.pbipagename = pbipagename; this.tooltip = tooltip; + this.obsolete = obsolete; } public XElement asXElement() @@ -25,7 +27,8 @@ public XElement asXElement() new XAttribute("name", name), new XAttribute("caption", caption), new XAttribute("pbipagename", pbipagename), - new XAttribute("tooltip", tooltip) + new XAttribute("tooltip", tooltip), + new XAttribute("obsolete", obsolete) ); return action; diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs index dc540d6f..92b6fc7e 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs @@ -1,11 +1,4 @@ -using CsvHelper.Configuration.Attributes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; +using System.Xml.Linq; namespace PayloadGenerator { @@ -18,13 +11,16 @@ internal class PBIPageDefinition string caption { get; set; } string aboutTitle { get; set; } string aboutText { get; set; } - string PBIReportId { get; set; } + string PBIReportIdFieldName { get; set; } string PBIReportName { get; set; } string PBIReportPage { get; set; } + string obsolete { get; set; } + string applicationArea { get; set; } public PBIPageDefinition( - string id, string name, string fileName, string caption, string aboutTitle - , string aboutText, string PBIReportId, string PBIReportName, string PBIReportPage + string id, string name, string fileName, string caption, string aboutTitle, + string aboutText, string PBIReportId, string PBIReportName, string PBIReportPage, + string obsolete, string applicationArea ) { this.id = id; @@ -33,9 +29,11 @@ public PBIPageDefinition( this.caption = caption; this.aboutTitle = aboutTitle; this.aboutText = aboutText; - this.PBIReportId = PBIReportId; + this.PBIReportIdFieldName = PBIReportId; this.PBIReportName = PBIReportName; this.PBIReportPage = PBIReportPage; + this.obsolete = obsolete; + this.applicationArea = applicationArea; } @@ -48,9 +46,11 @@ public XElement asXElement() new XAttribute("caption", caption), new XAttribute("aboutTitle", aboutTitle), new XAttribute("aboutText", aboutText), - new XAttribute("PBIReportId", PBIReportId), + new XAttribute("PBIReportIdFieldName", PBIReportIdFieldName), new XAttribute("PBIReportName", PBIReportName), - new XAttribute("PBIReportPage", PBIReportPage) + new XAttribute("PBIReportPage", PBIReportPage), + new XAttribute("obsolete", obsolete), + new XAttribute("applicationArea", applicationArea) ); return page; diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj index 4f4ae49b..00f98b8a 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj @@ -1,16 +1,16 @@ - + Exe - net7.0 + net8.0 enable enable - - - + + + diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs index a3961de8..47101b29 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; +using System.Xml.Linq; namespace PayloadGenerator { diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs index 66279ede..a90b9e98 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs @@ -1,20 +1,8 @@ -using System; -using System.Xml; -using System.Text; -using System.IO; -using Mono.Options; -using System.Collections.Generic; -using System.Reflection.Metadata; -using static System.Runtime.InteropServices.JavaScript.JSType; -using System.Xml.Serialization; -using System.Xml.Linq; -using System.Collections.ObjectModel; -using CsvHelper; -using System.Globalization; -using CsvHelper.Configuration; -using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; -using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using System.CommandLine; namespace PayloadGenerator @@ -23,45 +11,43 @@ class Program { static void Main(string[] args) { - // http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html - bool show_help = false; - string inputfile = ""; - string outputdir = ""; - string outputfile = ""; - - int idnumberstart = 50000; - - var p = new OptionSet() { - { "h|help", "show this message and exit", v => show_help = v != null }, - { "i|inputfile=", "input Excel file (required)", v => inputfile = v }, - { "outputdir=", "output directory", v => outputdir = v }, - { "outputfile=", "output file (required)", v => outputfile = v }, - { "idnumberstart=", "Id numbers for AL objects starts at this number (default is 50000)", v => idnumberstart = int.Parse( v ) }, + var rootCommand = new RootCommand("Power BI content - AL payload generator"); + var inputFileOption = new Option("--inputfile", "The input Excel file") + { + IsRequired = true }; - - List extra; - try + inputFileOption.AddAlias("--i"); + var outputFileOption = new Option("--outputfile", "The output file to be used as payload for the AL generator") { - extra = p.Parse(args); - } - catch (OptionException e) + IsRequired = true + }; + var outputDirOption = new Option( + "--outputdir", + description: "The output directory for the output file", + getDefaultValue: () => new DirectoryInfo(System.IO.Directory.GetCurrentDirectory()) + ); + rootCommand.AddOption(inputFileOption); + rootCommand.AddOption(outputFileOption); + rootCommand.AddOption(outputDirOption); + + rootCommand.SetHandler((inputFile, outputFile, outputDir) => { - Console.WriteLine(e.Message); - Console.WriteLine("Try using --help' for more information."); - Environment.Exit(0); - } + Run(inputFile.FullName, outputFile.FullName, outputDir.FullName); + }, inputFileOption, outputFileOption, outputDirOption); - if (show_help) + try { - ShowHelp(p); - Environment.Exit(0); + rootCommand.InvokeAsync(args); } - - if (inputfile.Equals("")) + catch (Exception ex) { - ShowHelp(p); - Environment.Exit(0); + Console.WriteLine(ex.Message); + Console.WriteLine("Try using --help' for more information."); + Environment.Exit(-1); } + } + public static void Run(string inputfile, string outputfile, string outputdir) + { Console.WriteLine("PBI embed app payload generator"); @@ -77,9 +63,9 @@ static void Main(string[] args) } Console.WriteLine("Worksheet '{0}'. Found : {1} rows", NamespaceSheetName, NamespaceRows.Count.ToString()); string ALNamespace = ""; - if (NamespaceRows.Count >= 2 && NamespaceRows[1].Length > 0) + if (NamespaceRows.Count >= 1 && NamespaceRows[0].Length > 0) { - ALNamespace = NamespaceRows[1][0]; + ALNamespace = NamespaceRows[0][0]; } var PBIReportsSheetName = "PBIReports"; @@ -122,17 +108,9 @@ static void Main(string[] args) if (outputfile.Equals("")) { Console.WriteLine("Output file parameter required."); - Environment.Exit(0); - } - - - if (outputdir.Equals("")) - { - outputdir = System.IO.Directory.GetCurrentDirectory(); + Environment.Exit(-1); } Console.WriteLine("Using directory for output files: " + outputdir); - - Console.WriteLine("Generating payload file..."); XDocument payloaddoc = GeneratePayload(ALNamespace, pages, rcExtensions, permSets); @@ -196,16 +174,6 @@ public static void SaveFile(string folder, string fileName, string content) } } - static void ShowHelp(OptionSet p) - { - Console.WriteLine("Usage: PayloadGenerator [OPTIONS]+"); - Console.WriteLine(); - Console.WriteLine("Options:"); - p.WriteOptionDescriptions(Console.Out); - - Console.WriteLine("-------------------"); - } - static private List readExcelWorksheet(string inputfile, string worksheetName) { List rows = new List(); @@ -216,18 +184,39 @@ static private List readExcelWorksheet(string inputfile, string worksh var sheet = workbookPart.Workbook.Descendants().FirstOrDefault(s => s.Name == worksheetName); var worksheetPart = (WorksheetPart)(workbookPart.GetPartById(sheet.Id)); var sheetData = worksheetPart.Worksheet.Elements().First(); + var columnRefs = new List(); + var regex = new Regex("\\d+"); foreach (var row in sheetData.Elements()) { - List cells = new List(); - - foreach (var cell in row.Elements()) + if (row.RowIndex == 1) { - cells.Add(GetCellValue(cell, workbookPart)); + foreach (var cell in row.Elements()) + { + columnRefs.Add(regex.Replace(cell.CellReference, "")); + } + } + else + { + List cells = new List(); + + foreach(var columnRef in columnRefs) + { + var query = row.Elements().Where(cell => regex.Replace(cell.CellReference, "") == columnRef).FirstOrDefault(); + + if (query == null) + { + cells.Add(""); + } + else + { + cells.Add(GetCellValue(query, workbookPart)); + } + } + + var cellArray = cells.ToArray(); + rows.Add(cellArray); } - - var cellArray = cells.ToArray(); - rows.Add(cellArray); } } return rows; @@ -246,8 +235,10 @@ static private void ExcelRowstoPBIPageDefinitions(List PBIReportRows, row[5], row[6], row[7], - row[8] - ); + row[8], + row[9], + row[10] + ); if (!row[0].Equals("id")) { @@ -267,7 +258,9 @@ static private void ExcelRowstoRCExtensionDefinitions(List RCExtension row[2], row[3], row[4], - row[5] + row[5], + row[6], + row[7] ); if (!row[0].Equals("id")) @@ -287,7 +280,8 @@ static private void ExcelRowstoRCExtensionActionDefinitions(List RCExt row[1], row[2], row[3], - row[4] + row[4], + row[5] ); if (!row[0].Equals("rcextensionname")) @@ -320,7 +314,7 @@ static private string GetCellValue(Cell cell, WorkbookPart workbookPart) { if (cell == null) { - return null; + return ""; } var value = cell.CellFormula != null @@ -369,39 +363,6 @@ static private string GetCellValue(Cell cell, WorkbookPart workbookPart) break; } } - //switch (cell.DataType.Value) - //{ - // case CellValues.SharedString: - - // // For shared strings, look up the value in the - // // shared strings table. - // var stringTable = - // workbookPart.GetPartsOfType() - // .FirstOrDefault(); - - // // If the shared string table is missing, something - // // is wrong. Return the index that is in - // // the cell. Otherwise, look up the correct text in - // // the table. - // if (stringTable != null) - // { - // value = - // stringTable.SharedStringTable - // .ElementAt(int.Parse(value)).InnerText; - // } - // break; - - // case CellValues.Boolean: - // switch (value) - // { - // case "0": - // value = "FALSE"; - // break; - // default: - // value = "TRUE"; - // break; - // } - // break; } return value; diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs index 485ede42..3b0a9c27 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; +using System.Xml.Linq; namespace PayloadGenerator { @@ -16,6 +10,8 @@ internal class RCExtensionDefinition string extends{ get; set; } string where { get; set; } string tooltip { get; set; } + string rolecenternamespace { get; set; } + string image { get; set; } //id = "50140" //name = "BusinessManagerRoleCenterExt" @@ -36,7 +32,9 @@ public RCExtensionDefinition( string filename, string extends, string where, - string tooltip + string tooltip, + string rolecenternamespace, + string image ) { this.id = id; @@ -45,6 +43,8 @@ string tooltip this.extends = extends; this.where = where; this.tooltip = tooltip; + this.rolecenternamespace = rolecenternamespace; + this.image = image; } @@ -56,7 +56,9 @@ public XElement asXElement() new XAttribute("filename", filename), new XAttribute("extends", extends), new XAttribute("where", where), - new XAttribute("tooltip", tooltip) + new XAttribute("tooltip", tooltip), + new XAttribute("rolecenternamespace", rolecenternamespace), + new XAttribute("image", image) ); foreach(ActionDefinition action in actions) From 3d99927266083d34e6ff4aed319bf9e27d386a85 Mon Sep 17 00:00:00 2001 From: Enrico Cimitan Date: Mon, 10 Feb 2025 14:48:43 +0100 Subject: [PATCH 2/2] Compilation --- .../PBIEmbedGenerator.csproj | 6 +- .../PBIEmbedGenerator/Program.cs | 96 +++++++++++----- .../PBIPayloadGenerator/PBIPageDefinition.cs | 9 +- .../PayloadGenerator.csproj | 10 +- .../PBIPayloadGenerator/PermSetDefinition.cs | 8 +- .../PBIPayloadGenerator/Program.cs | 107 +++++++++++++----- .../RCExtensionDefinition.cs | 8 +- 7 files changed, 172 insertions(+), 72 deletions(-) diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj index 3960a212..d7285230 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/PBIEmbedGenerator.csproj @@ -1,8 +1,8 @@ - + Exe - net8.0 + net7.0 @@ -14,7 +14,7 @@ - + diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs index c82000cf..58a64227 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIEmbedGenerator/Program.cs @@ -1,9 +1,10 @@ -using PBIEmbedGenerator.Properties; -using System; -using System.CommandLine; -using System.IO; -using System.Text; +using System; using System.Xml; +using System.Text; +using System.IO; +using Mono.Options; +using System.Collections.Generic; +using PBIEmbedGenerator.Properties; namespace APIQueryGenerator { @@ -11,38 +12,43 @@ class Program { static void Main(string[] args) { - var inputFileOption = new Option("--inputfile", "The XML payload input file") - { - IsRequired = true - }; - inputFileOption.AddAlias("--i"); - var outputDirOption = new Option("--outputdir", "The output directory where the AL files will be generated") - { - IsRequired = true + // http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html + bool show_help = false; + string inputfile = ""; + string outputdir = ""; + Version version = new Version(); + + var p = new OptionSet() { + { "h|help", "show this message and exit", v => show_help = v != null }, + { "i|inputfile=", "input xml file (required)", v => inputfile = v }, + { "o|outputdir=", "output directory (if not specified, then input file name will be used)", v => outputdir = v }, + { "v|version=", "target Business Central version", v => version = new Version(v) } }; - outputDirOption.AddAlias("--o"); - var rootCommand = new RootCommand("Power BI content - AL generator"); - rootCommand.AddOption(inputFileOption); - rootCommand.AddOption(outputDirOption); - rootCommand.SetHandler((inputFile, outputDir) => + List extra; + try + { + extra = p.Parse(args); + } + catch (OptionException e) { - Run(inputFile.FullName, outputDir.FullName); - }, inputFileOption, outputDirOption); + Console.WriteLine(e.Message); + Console.WriteLine("Try using --help' for more information."); + Environment.Exit(0); + } - try + if (show_help) { - rootCommand.InvokeAsync(args); + ShowHelp(p); + Environment.Exit(0); } - catch (Exception ex) + + if (inputfile.Equals("")) { - Console.WriteLine(ex.Message); - Environment.Exit(-1); + ShowHelp(p); + Environment.Exit(0); } - } - static void Run(string inputfile, string outputdir) - { Console.WriteLine("PBI embed page AL code generator"); Console.WriteLine("------------------------"); @@ -85,7 +91,7 @@ static void Run(string inputfile, string outputdir) Console.WriteLine("Found {0} pages", pages.SelectNodes("page").Count.ToString()); foreach (XmlNode page in pages.SelectNodes("page")) { - var content = GeneratePBIEmbedPageCode(alNamespace, page); + var content = GeneratePBIEmbedPageCode(alNamespace, page, version); var filename = page.Attributes["filename"].Value; SaveFile(outputdir, filename, content); Console.WriteLine(filename); @@ -173,7 +179,7 @@ public static void GeneratePBIRCExtensionActionCode(XmlNode action, StringBuilde } } - public static string GeneratePBIEmbedPageCode(string alNamespace, XmlNode query) + public static string GeneratePBIEmbedPageCode(string alNamespace, XmlNode query, Version version) { StringBuilder sb = new StringBuilder(); StringBuilder additionalProperties = new StringBuilder(); @@ -275,5 +281,35 @@ public static void SaveFile(string folder, string fileName, string content) } } } + + static void ShowHelp(OptionSet p) + { + Console.WriteLine("Usage: APIQueryGenerator [OPTIONS]+"); + Console.WriteLine(); + Console.WriteLine("Options:"); + p.WriteOptionDescriptions(Console.Out); + + Console.WriteLine("-------------------"); + var exampleXML = """ + + + + + + + + + + + + + +"""; + + Console.WriteLine("Example input file"); + Console.WriteLine(exampleXML); + Console.WriteLine("-------------------"); + } + } } diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs index 92b6fc7e..d4a9e896 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PBIPageDefinition.cs @@ -1,4 +1,11 @@ -using System.Xml.Linq; +using CsvHelper.Configuration.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; namespace PayloadGenerator { diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj index 00f98b8a..4f4ae49b 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PayloadGenerator.csproj @@ -1,16 +1,16 @@ - + Exe - net8.0 + net7.0 enable enable - - - + + + diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs index 47101b29..a3961de8 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/PermSetDefinition.cs @@ -1,4 +1,10 @@ -using System.Xml.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; namespace PayloadGenerator { diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs index a90b9e98..fbf9ffa9 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/Program.cs @@ -1,8 +1,8 @@ using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; +using Mono.Options; using System.Text.RegularExpressions; using System.Xml.Linq; -using System.CommandLine; namespace PayloadGenerator @@ -11,43 +11,45 @@ class Program { static void Main(string[] args) { - var rootCommand = new RootCommand("Power BI content - AL payload generator"); - var inputFileOption = new Option("--inputfile", "The input Excel file") - { - IsRequired = true - }; - inputFileOption.AddAlias("--i"); - var outputFileOption = new Option("--outputfile", "The output file to be used as payload for the AL generator") - { - IsRequired = true + // http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html + bool show_help = false; + string inputfile = ""; + string outputdir = ""; + string outputfile = ""; + + int idnumberstart = 50000; + + var p = new OptionSet() { + { "h|help", "show this message and exit", v => show_help = v != null }, + { "i|inputfile=", "input Excel file (required)", v => inputfile = v }, + { "outputdir=", "output directory", v => outputdir = v }, + { "outputfile=", "output file (required)", v => outputfile = v }, + { "idnumberstart=", "Id numbers for AL objects starts at this number (default is 50000)", v => idnumberstart = int.Parse( v ) }, }; - var outputDirOption = new Option( - "--outputdir", - description: "The output directory for the output file", - getDefaultValue: () => new DirectoryInfo(System.IO.Directory.GetCurrentDirectory()) - ); - rootCommand.AddOption(inputFileOption); - rootCommand.AddOption(outputFileOption); - rootCommand.AddOption(outputDirOption); - - rootCommand.SetHandler((inputFile, outputFile, outputDir) => - { - Run(inputFile.FullName, outputFile.FullName, outputDir.FullName); - }, inputFileOption, outputFileOption, outputDirOption); + List extra; try { - rootCommand.InvokeAsync(args); + extra = p.Parse(args); } - catch (Exception ex) + catch (OptionException e) { - Console.WriteLine(ex.Message); + Console.WriteLine(e.Message); Console.WriteLine("Try using --help' for more information."); - Environment.Exit(-1); + Environment.Exit(0); + } + + if (show_help) + { + ShowHelp(p); + Environment.Exit(0); + } + + if (inputfile.Equals("")) + { + ShowHelp(p); + Environment.Exit(0); } - } - public static void Run(string inputfile, string outputfile, string outputdir) - { Console.WriteLine("PBI embed app payload generator"); @@ -174,6 +176,16 @@ public static void SaveFile(string folder, string fileName, string content) } } + static void ShowHelp(OptionSet p) + { + Console.WriteLine("Usage: PayloadGenerator [OPTIONS]+"); + Console.WriteLine(); + Console.WriteLine("Options:"); + p.WriteOptionDescriptions(Console.Out); + + Console.WriteLine("-------------------"); + } + static private List readExcelWorksheet(string inputfile, string worksheetName) { List rows = new List(); @@ -314,7 +326,7 @@ static private string GetCellValue(Cell cell, WorkbookPart workbookPart) { if (cell == null) { - return ""; + return null; } var value = cell.CellFormula != null @@ -363,6 +375,39 @@ static private string GetCellValue(Cell cell, WorkbookPart workbookPart) break; } } + //switch (cell.DataType.Value) + //{ + // case CellValues.SharedString: + + // // For shared strings, look up the value in the + // // shared strings table. + // var stringTable = + // workbookPart.GetPartsOfType() + // .FirstOrDefault(); + + // // If the shared string table is missing, something + // // is wrong. Return the index that is in + // // the cell. Otherwise, look up the correct text in + // // the table. + // if (stringTable != null) + // { + // value = + // stringTable.SharedStringTable + // .ElementAt(int.Parse(value)).InnerText; + // } + // break; + + // case CellValues.Boolean: + // switch (value) + // { + // case "0": + // value = "FALSE"; + // break; + // default: + // value = "TRUE"; + // break; + // } + // break; } return value; diff --git a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs index 3b0a9c27..240f91aa 100644 --- a/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs +++ b/samples/PowerBi/EmbedYourPBIApp/PBIPayloadGenerator/RCExtensionDefinition.cs @@ -1,4 +1,10 @@ -using System.Xml.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; namespace PayloadGenerator {