Skip to content

Commit

Permalink
Refactor Input Handling and App Creation code (#613)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Petrochuk <[email protected]>
  • Loading branch information
cwduncan and petrochuk authored Apr 2, 2024
1 parent 94d4b6f commit faad4cd
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 158 deletions.
54 changes: 54 additions & 0 deletions samples/MSAppGenerator/AppCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.PowerPlatform.PowerApps.Persistence.Extensions;
using Microsoft.PowerPlatform.PowerApps.Persistence.MsApp;

namespace MSAppGenerator;

public class AppCreator
{
/// <summary>
/// Configures default services for generating the MSApp representation
/// </summary>
private static IServiceProvider ConfigureServiceProvider()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddPowerAppsPersistence(true);
serviceCollection.AddSingleton<IAppGeneratorFactory, AppGeneratorFactory>();
var serviceProvider = serviceCollection.BuildServiceProvider();
return serviceProvider;
}

IServiceProvider _serviceProvider { get; set; }

public AppCreator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public AppCreator()
{
_serviceProvider = ConfigureServiceProvider();
}

/// <summary>
/// Attempt to do specified app creation
/// </summary>
public void CreateMSApp(bool interactive, string fullPathToMsApp, int numScreens, IList<string>? controlsinfo)
{
// Create a new empty MSApp
using var msapp = _serviceProvider.GetRequiredService<IMsappArchiveFactory>().Create(fullPathToMsApp);

// Select Generator based off specified mode
var generator = _serviceProvider.GetRequiredService<IAppGeneratorFactory>().Create(interactive);

// Generate the app
msapp.App = generator.GenerateApp(Path.GetFileNameWithoutExtension(fullPathToMsApp),
numScreens, controlsinfo);

// Output the MSApp to the path provided
msapp.Save();
}
}
1 change: 0 additions & 1 deletion samples/MSAppGenerator/InteractiveGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public App GenerateApp(string filePath, int numScreens, IList<string>? controls)
app.Screens.Add(_controlFactory.CreateScreen(screenname, children: childlist.ToArray()));
}
}

}
else if (input?.ToLower()[0] == 'n')
{
Expand Down
8 changes: 7 additions & 1 deletion samples/MSAppGenerator/MSAppGenerator.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<!-- <TargetFramework>net8.0</TargetFramework> -->
<TargetFrameworks>$(TargetFrameworks);net8.0;net8.0-windows10.0.19041.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="YamlDotNet" Version="15.1.1" />
</ItemGroup>

<ItemGroup>
<!-- This reference will be replaced with Nuget package reference -->
<Reference Include="Microsoft.PowerPlatform.PowerApps.Persistence">
Expand Down
41 changes: 7 additions & 34 deletions samples/MauiMsApp/CreatePage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,6 @@ public CreatePage()
InitializeComponent();
}


/// <summary>
/// Attempt to do specified app creation
/// </summary>
private async Task CreateMSApp(bool interactive, string fullPathToMsApp, int numScreens, IList<string>? controlsinfo)
{
try
{
// Setup services for creating MSApp representation
var provider = Handler!.MauiContext!.Services;

// Create a new empty MSApp
using var msapp = provider.GetRequiredService<IMsappArchiveFactory>().Create(fullPathToMsApp);

// Select Generator based off specified mode
var generator = provider.GetRequiredService<IAppGeneratorFactory>().Create(interactive);

// Generate the app
msapp.App = generator.GenerateApp(Path.GetFileNameWithoutExtension(fullPathToMsApp),
numScreens, controlsinfo);

// Output the MSApp to the path provided
msapp.Save();

await DisplayAlert("Success", "You are now a PowerApps Pro Developer!", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Alert", "Something went wrong:\n" + ex.Message, "OK");
}
}

#pragma warning disable CA1822 // Mark members as static
private async void OnCreateClicked(object sender, EventArgs e)
#pragma warning restore CA1822 // Mark members as static
Expand All @@ -55,11 +23,16 @@ private async void OnCreateClicked(object sender, EventArgs e)
int numScreens;
var result = int.TryParse(_numScreensEntry.Text, out numScreens);
var controlTemplates = _controlTemplatesEntry.Text.Split(' ');
await CreateMSApp(false, filePath, numScreens, controlTemplates);

var creator = new AppCreator(Handler!.MauiContext!.Services);
creator.CreateMSApp(false, filePath, numScreens, controlTemplates);

await DisplayAlert("Success", "You are now a PowerApps Pro Developer!", "OK");
}
catch (Exception)
catch (Exception ex)
{
// The user canceled or something went wrong
await DisplayAlert("Alert", "Something went wrong: " + ex.Message, "OK");
}
}

Expand Down
6 changes: 5 additions & 1 deletion samples/MauiMsApp/MauiMsApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.6" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.6" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="YamlDotNet" Version="15.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\MSAppGenerator\MSAppGenerator.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion samples/MauiMsApp/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static MauiApp CreateMauiApp()
private static MauiAppBuilder RegisterMsAppPersistence(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddPowerAppsPersistence(useDefaultTemplates: true);
mauiAppBuilder.Services.AddSingleton<IAppGeneratorFactory, AppGeneratorFactory>();
mauiAppBuilder.Services.AddTransient<IAppGeneratorFactory, AppGeneratorFactory>();

return mauiAppBuilder;
}
Expand Down
120 changes: 120 additions & 0 deletions samples/Test.AppWriter/InputProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.CommandLine;
using MSAppGenerator;

namespace Test.AppWriter;

internal class InputProcessor
{
/// <summary>
/// Validate that the provided filepath is accessible and not an existing file
/// </summary>
private static bool ValidateFilePath(string filePath, out string error)
{
error = string.Empty;
if (!File.Exists(filePath))
return true;

Console.WriteLine($"Warning: File '{filePath}' already exists");
Console.Write("Overwrite? ([y]/n) - enter for yes: ");

var input = Console.ReadKey();
Console.WriteLine();
if (input.Key == ConsoleKey.Enter || input.Key == ConsoleKey.Y)
{
try
{
File.Delete(filePath);
}
catch (IOException ex)
{
error = $"Error: {ex.Message}";
return false;
}
return true;
}

error = $"Unable to overwrite file";
return false;
}

/// <summary>
/// Function to bind to the Create command and call App Creation code
/// </summary>
private static void CreateFunction(bool interactive, string fullPathToMsApp, int numScreens, IList<string>? controlsinfo)
{
var creator = new AppCreator();

try
{
creator.CreateMSApp(interactive, fullPathToMsApp, numScreens, controlsinfo);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

/// <summary>
/// Configures and returns the root command to process commandline arguments
/// </summary>
public static RootCommand GetRootCommand()
{
var interactiveOption = new Option<bool>(
name: "--interactive",
description: "Enables interactive mode for MSApp creation",
getDefaultValue: () => false // If --interactive is not specified, default to argument based creation
);
var filePathOption = new Option<FileInfo?>(
name: "--filepath",
description: "(string) The path where the msapp file should be generated, including filename and extension",
parseArgument: result =>
{
var filePath = result.Tokens.Single().Value;
if (ValidateFilePath(filePath, out var error))
return new FileInfo(filePath);
result.ErrorMessage = error;
return null;
}
)
{ IsRequired = true };
var numScreensOption = new Option<int>(
name: "--numscreens",
description: "(integer) The number of screens to generate in the App",
getDefaultValue: () => 1
);
numScreensOption.AddValidator(result =>
{
if (result.GetValueForOption(numScreensOption) < 0)
{
result.ErrorMessage = "Number of screens must be greater than 0";
}
});
var controlsOptions = new Option<IList<string>>(
name: "--controls",
description: "(list of string) A list of control templates (i.e. Button Label [Template]...)")
{ AllowMultipleArgumentsPerToken = true };

var rootCommand = new RootCommand("Test Writer for MSApp files.");
var createCommand = new Command("create", "Create a new MSApp at the specified path.")
{
interactiveOption,
filePathOption,
numScreensOption,
controlsOptions
};

createCommand.SetHandler((interactive, filepath, numscreens, controls) =>
{
CreateFunction(interactive, filepath!.FullName, numscreens, controls);
}, interactiveOption, filePathOption, numScreensOption, controlsOptions);

rootCommand.AddCommand(createCommand);

return rootCommand;
}
}
Loading

0 comments on commit faad4cd

Please sign in to comment.