Skip to content

Commit

Permalink
improve user experience of Module Creator flow
Browse files Browse the repository at this point in the history
  • Loading branch information
sbwalker committed Nov 25, 2020
1 parent 5e42ab8 commit 4401dba
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 80 deletions.
175 changes: 111 additions & 64 deletions Oqtane.Client/Modules/Admin/ModuleCreator/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,87 @@
@inject IModuleDefinitionService ModuleDefinitionService
@inject IModuleService ModuleService
@inject ISystemService SystemService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@using System.Text.RegularExpressions

<table class="table table-borderless">
<tr>
<td>
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
</td>
<td>
<input id="owner" class="form-control" @bind="@_owner" />
</td>
</tr>
<tr>
<td>
<Label For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation." ResourceKey="ModuleName">Module Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_module" />
</td>
</tr>
<tr>
<td>
<Label For="description" HelpText="Enter s short description for the module" ResourceKey="Description">Description: </Label>
</td>
<td>
<textarea id="description" class="form-control" @bind="@_description" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the Oqtane solution. External modules are created outside of the Oqtane solution." ResourceKey="Template">Template: </Label>
</td>
<td>
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
<option value="-">&lt;@Localizer["Select Template"]&gt;</option>
<option value="internal">@Localizer["Internal"]</option>
<option value="external">@Localizer["External"]</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
</td>
<td>
<select id="reference" class="form-control" @bind="@_reference">
@foreach (string version in Constants.ReleaseVersions.Split(','))
{
if (Version.Parse(version).CompareTo(Version.Parse("2.0.0")) >= 0)
{
<option value="@(version)">@(version)</option>
}
}
<option value="local">@Localizer["Local Version"]</option>
</select>
</td>
</tr>
@if (!string.IsNullOrEmpty(_location))
{
@if (string.IsNullOrEmpty(_moduledefinitionname))
{
<table class="table table-borderless">
<tr>
<td>
<Label For="location" HelpText="Location where the module will be created" ResourceKey="Location">Location: </Label>
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_location" readonly />
<input id="owner" class="form-control" @bind="@_owner" />
</td>
</tr>
}
</table>

<button type="button" class="btn btn-success" @onclick="CreateModule">@Localizer["Create Module"]</button>
<tr>
<td>
<Label For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation." ResourceKey="ModuleName">Module Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_module" />
</td>
</tr>
<tr>
<td>
<Label For="description" HelpText="Enter a short description for the module" ResourceKey="Description">Description: </Label>
</td>
<td>
<textarea id="description" class="form-control" @bind="@_description" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the framework solution. External modules are created outside of the framework solution." ResourceKey="Template">Template: </Label>
</td>
<td>
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
<option value="-">&lt;@Localizer["Select Template"]&gt;</option>
<option value="internal">@Localizer["Internal"]</option>
<option value="external">@Localizer["External"]</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
</td>
<td>
<select id="reference" class="form-control" @bind="@_reference">
@foreach (string version in Constants.ReleaseVersions.Split(','))
{
if (Version.Parse(version).CompareTo(Version.Parse("2.0.0")) >= 0)
{
<option value="@(version)">@(version)</option>
}
}
<option value="local">@Localizer["Local Version"]</option>
</select>
</td>
</tr>
@if (!string.IsNullOrEmpty(_location))
{
<tr>
<td>
<Label For="location" HelpText="Location where the module will be created" ResourceKey="Location">Location: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_location" readonly />
</td>
</tr>
}
</table>
<button type="button" class="btn btn-success" @onclick="CreateModule">@Localizer["Create Module"]</button>
}
else
{
<button type="button" class="btn btn-success" @onclick="ActivateModule">@Localizer["Activate Module"]</button>
}

@code {
private string _moduledefinitionname = "";
private string _owner = string.Empty;
private string _module = string.Empty;
private string _description = string.Empty;
Expand All @@ -86,15 +94,35 @@

public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;

protected override void OnInitialized()
{
_moduledefinitionname = SettingService.GetSetting(ModuleState.Settings, "ModuleDefinitionName", "");
if (string.IsNullOrEmpty(_moduledefinitionname))
{
_owner = ModuleState.Title;
_module = ModuleState.Title;
_description = ModuleState.Title;
}
else
{
AddModuleMessage("Once You Have Compiled The Module And Restarted The Application You Can Activate The Module Below", MessageType.Info);
}
}

private async Task CreateModule()
{
try
{
if (IsValid(_owner) && IsValid(_module) && _template != "-")
{
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference };
await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition, ModuleState.ModuleId);
AddModuleMessage("The Source Code For Your Module Has Been Created And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must Restart Your Application.", MessageType.Success);
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);

var settings = ModuleState.Settings;
SettingService.SetSetting(settings, "ModuleDefinitionName", moduleDefinition.ModuleDefinitionName);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);

AddModuleMessage("The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href=\"" + NavigateUrl("admin/system") + "\">Restart</a> Your Application To Apply These Changes.", MessageType.Success);
}
else
{
Expand All @@ -107,6 +135,25 @@
}
}

private async Task ActivateModule()
{
try
{
if (!string.IsNullOrEmpty(_moduledefinitionname))
{
Module module = await ModuleService.GetModuleAsync(ModuleState.ModuleId);
module.ModuleDefinitionName = _moduledefinitionname;
await ModuleService.UpdateModuleAsync(module);
StateHasChanged();
NavigationManager.NavigateTo(NavigateUrl());
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Activating Module");
}
}

private bool IsValid(string name)
{
// must contain letters, underscores and digits and first character must be letter or underscore
Expand Down
4 changes: 2 additions & 2 deletions Oqtane.Client/Services/Interfaces/IModuleDefinitionService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using Oqtane.UI;
using System.Collections.Generic;
using System.Threading.Tasks;
Expand All @@ -12,6 +12,6 @@ public interface IModuleDefinitionService
Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
Task InstallModuleDefinitionsAsync();
Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId);
Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId);
Task<ModuleDefinition> CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
}
}
6 changes: 3 additions & 3 deletions Oqtane.Client/Services/ModuleDefinitionService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
Expand Down Expand Up @@ -49,9 +49,9 @@ public async Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId
await DeleteAsync($"{Apiurl}/{moduleDefinitionId}?siteid={siteId}");
}

public async Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId)
public async Task<ModuleDefinition> CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition)
{
await PostJsonAsync($"{Apiurl}?moduleid={moduleId}", moduleDefinition);
return await PostJsonAsync($"{Apiurl}", moduleDefinition);
}
}
}
16 changes: 5 additions & 11 deletions Oqtane.Server/Controllers/ModuleDefinitionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,22 @@ namespace Oqtane.Controllers
public class ModuleDefinitionController : Controller
{
private readonly IModuleDefinitionRepository _moduleDefinitions;
private readonly IModuleRepository _modules;
private readonly ITenantRepository _tenants;
private readonly ISqlRepository _sql;
private readonly IUserPermissions _userPermissions;
private readonly IInstallationManager _installationManager;
private readonly IWebHostEnvironment _environment;
private readonly IConfigurationRoot _config;
private readonly IServiceProvider _serviceProvider;
private readonly ILogManager _logger;

public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules,ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IConfigurationRoot config, IServiceProvider serviceProvider, ILogManager logger)
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ILogManager logger)
{
_moduleDefinitions = moduleDefinitions;
_modules = modules;
_tenants = tenants;
_sql = sql;
_userPermissions = userPermissions;
_installationManager = installationManager;
_environment = environment;
_config = config;
_serviceProvider = serviceProvider;
_logger = logger;
}
Expand Down Expand Up @@ -166,7 +162,7 @@ public void Delete(int id, int siteid)
// POST api/<controller>?moduleid=x
[HttpPost]
[Authorize(Roles = RoleNames.Host)]
public void Post([FromBody] ModuleDefinition moduleDefinition, string moduleid)
public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition)
{
if (ModelState.IsValid)
{
Expand All @@ -190,19 +186,17 @@ public void Post([FromBody] ModuleDefinition moduleDefinition, string moduleid)
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition);

Models.Module module = _modules.GetModule(int.Parse(moduleid));
module.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName;
_modules.UpdateModule(module);

if (moduleDefinition.Template == "internal")
{
// add embedded resources to project
// add embedded resources to project file
List<string> resources = new List<string>();
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".1.0.0.sql"));
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".Uninstall.sql"));
EmbedResourceFiles(Utilities.PathCombine(rootPath, "Oqtane.Server", "Oqtane.Server.csproj"), resources);
}
}

return moduleDefinition;
}

private void ProcessTemplatesRecursively(DirectoryInfo current, string rootPath, string rootFolder, string templatePath, ModuleDefinition moduleDefinition)
Expand Down

0 comments on commit 4401dba

Please sign in to comment.