feat: save caddy file on edit and add new
This commit is contained in:
@@ -21,7 +21,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
<Folder Include="Repositories\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<script src="_content/BlazorMonaco/jsInterop.js"></script>
|
||||
<script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js"></script>
|
||||
<script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js"></script>
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,6 +1,4 @@
|
||||
@attribute [StreamRendering]
|
||||
@using CaddyManager.Contracts.Caddy
|
||||
@inject ICaddyService CaddyService
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
@@ -9,7 +7,8 @@
|
||||
ShrinkLabel="true"
|
||||
Disabled="@(!IsNew)"></MudTextField>
|
||||
<MudText Typo="Typo.caption" Style="padding-left: 18px; padding-bottom: 8px;">File content</MudText>
|
||||
<StandaloneCodeEditor ConstructionOptions="@EditorConstructionOptions"
|
||||
<StandaloneCodeEditor @ref="_codeEditor"
|
||||
ConstructionOptions="@EditorConstructionOptions"
|
||||
CssClass="caddy-file-editor"></StandaloneCodeEditor>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using BlazorMonaco.Editor;
|
||||
using CaddyManager.Contracts.Caddy;
|
||||
using CaddyManager.Models.Caddy;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
@@ -8,31 +9,34 @@ namespace CaddyManager.Components.Pages.CaddyfileEditor;
|
||||
public partial class CaddyfileEditor : ComponentBase
|
||||
{
|
||||
private string _caddyConfigurationContent = string.Empty;
|
||||
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
private StandaloneCodeEditor _codeEditor = null!;
|
||||
|
||||
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the Caddy configuration file is new
|
||||
/// </summary>
|
||||
private bool IsNew { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
[Parameter] public string FileName { get; set; } = string.Empty;
|
||||
|
||||
[Inject] private ICaddyService CaddyService { get; set; } = null!;
|
||||
|
||||
[Inject] private ISnackbar Snackbar { get; set; } = null!;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
IsNew = string.IsNullOrWhiteSpace(FileName);
|
||||
|
||||
|
||||
if (!IsNew)
|
||||
{
|
||||
// Load the content of the Caddy configuration file
|
||||
_caddyConfigurationContent = CaddyService.GetCaddyConfigurationContent(FileName);
|
||||
}
|
||||
|
||||
|
||||
return base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
|
||||
private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
|
||||
{
|
||||
return new StandaloneEditorConstructionOptions
|
||||
@@ -44,7 +48,25 @@ public partial class CaddyfileEditor : ComponentBase
|
||||
};
|
||||
}
|
||||
|
||||
private void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||
private async Task Submit()
|
||||
{
|
||||
var response = CaddyService.SaveCaddyConfiguration(new CaddySaveConfigurationRequest
|
||||
{
|
||||
IsNew = IsNew,
|
||||
FileName = FileName,
|
||||
Content = await _codeEditor.GetValue(),
|
||||
});
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
Snackbar.Add($"{FileName} Caddy configuration saved successfully", Severity.Success);
|
||||
MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add("Failed to save Caddy configuration", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Cancel() => MudDialog.Cancel();
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
@page "/caddyfile"
|
||||
@attribute [StreamRendering]
|
||||
@using CaddyManager.Contracts.Caddy
|
||||
@inject ICaddyService CaddyService
|
||||
|
||||
<PageTitle>Global Caddyfile</PageTitle>
|
||||
|
||||
@@ -12,7 +10,9 @@
|
||||
</MudText>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<StandaloneCodeEditor ConstructionOptions="@EditorConstructionOptions" CssClass="caddy-file-editor global-caddy"></StandaloneCodeEditor>
|
||||
<MudText Typo="Typo.caption" Style="padding-left: 18px; padding-bottom: 8px;">File content</MudText>
|
||||
<StandaloneCodeEditor @ref="_codeEditor" ConstructionOptions="@EditorConstructionOptions"
|
||||
CssClass="caddy-file-editor global-caddy"></StandaloneCodeEditor>
|
||||
<MudDivider/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
@@ -1,11 +1,18 @@
|
||||
using BlazorMonaco.Editor;
|
||||
using CaddyManager.Contracts.Caddy;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace CaddyManager.Components.Pages;
|
||||
|
||||
public partial class Caddyfile: ComponentBase
|
||||
public partial class CaddyfilePage : ComponentBase
|
||||
{
|
||||
private string _caddyConfigurationContent = string.Empty;
|
||||
private StandaloneCodeEditor _codeEditor = null!;
|
||||
|
||||
[Inject] private ICaddyService CaddyService { get; set; } = null!;
|
||||
|
||||
[Inject] private ISnackbar Snackbar { get; set; } = null!;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
@@ -13,7 +20,7 @@ public partial class Caddyfile: ComponentBase
|
||||
_caddyConfigurationContent = CaddyService.GetCaddyGlobalConfigurationContent();
|
||||
return base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
|
||||
private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
|
||||
{
|
||||
return new StandaloneEditorConstructionOptions
|
||||
@@ -23,12 +30,21 @@ public partial class Caddyfile: ComponentBase
|
||||
Value = _caddyConfigurationContent,
|
||||
};
|
||||
}
|
||||
|
||||
private void Submit()
|
||||
|
||||
private async Task Submit()
|
||||
{
|
||||
// CaddyService.SaveCaddyGlobalConfigurationContent(_caddyConfigurationContent);
|
||||
var response = CaddyService.SaveCaddyGlobalConfiguration(await _codeEditor.GetValue());
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
Snackbar.Add("Caddy configuration saved successfully", Severity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add("Failed to save Caddy configuration", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
// CaddyService.GetCaddyGlobalConfigurationContent();
|
||||
@@ -1,8 +1,5 @@
|
||||
@page "/"
|
||||
@attribute [StreamRendering]
|
||||
@using CaddyManager.Contracts.Caddy
|
||||
@inject ICaddyService CaddyService
|
||||
@inject IDialogService DialogService
|
||||
|
||||
<PageTitle>Reverse proxy configurations</PageTitle>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using CaddyManager.Contracts.Caddy;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
@@ -7,20 +8,28 @@ public partial class ReverseProxiesPage : ComponentBase
|
||||
{
|
||||
private List<string> _availableCaddyConfigurations = [];
|
||||
private IReadOnlyCollection<string> _selectedCaddyConfigurations = [];
|
||||
|
||||
[Inject]
|
||||
private ICaddyService CaddyService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; set; } = null!;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
_availableCaddyConfigurations = CaddyService.GetExistingCaddyConfigurations();
|
||||
return base.OnInitializedAsync();
|
||||
if (firstRender)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to help open the dialog to create a new reverse proxy configuration
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Task NewReverseProxy()
|
||||
private async Task NewReverseProxy()
|
||||
{
|
||||
return DialogService.ShowAsync<CaddyfileEditor.CaddyfileEditor>("New configuration",
|
||||
var dialog = await DialogService.ShowAsync<CaddyfileEditor.CaddyfileEditor>("New configuration",
|
||||
options: new DialogOptions
|
||||
{
|
||||
FullWidth = true,
|
||||
@@ -29,5 +38,21 @@ public partial class ReverseProxiesPage : ComponentBase
|
||||
{
|
||||
{ "FileName", string.Empty }
|
||||
});
|
||||
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (result is { Data: bool, Canceled: false } && (bool)result.Data)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the latest information from the server
|
||||
/// </summary>
|
||||
private void Refresh()
|
||||
{
|
||||
_availableCaddyConfigurations = CaddyService.GetExistingCaddyConfigurations();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
@using CaddyManager.Contracts.Caddy
|
||||
@attribute [StreamRendering]
|
||||
@inject ICaddyService CaddyService
|
||||
@inject IDialogService DialogService
|
||||
|
||||
<MudListItem T="string" Text="@FileName" OnClick="Edit" OnClickPreventDefault="true">
|
||||
<MudContainer Class="d-flex flex-row flex-grow-1 gap-4">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using CaddyManager.Contracts.Caddy;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
@@ -10,6 +11,12 @@ public partial class ReverseProxyItem : ComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ICaddyService CaddyService { get; set; } = null!;
|
||||
|
||||
private Task Edit()
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using CaddyManager.Models.Caddy;
|
||||
|
||||
namespace CaddyManager.Contracts.Caddy;
|
||||
|
||||
/// <summary>
|
||||
@@ -24,4 +26,18 @@ public interface ICaddyService
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetCaddyGlobalConfigurationContent();
|
||||
|
||||
/// <summary>
|
||||
/// Method to help save a Caddy configuration file
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
CaddyOperationResponse SaveCaddyConfiguration(CaddySaveConfigurationRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Method to help save the global Caddyfile configuration
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
CaddyOperationResponse SaveCaddyGlobalConfiguration(string content);
|
||||
}
|
||||
17
CaddyManager/Models/Caddy/CaddyOperationResponse.cs
Normal file
17
CaddyManager/Models/Caddy/CaddyOperationResponse.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace CaddyManager.Models.Caddy;
|
||||
|
||||
/// <summary>
|
||||
/// Class to wrap the response of a generic Caddy operation
|
||||
/// </summary>
|
||||
public class CaddyOperationResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates if the operation was successful
|
||||
/// </summary>
|
||||
public bool Success { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Message to describe the operation result to provide more context
|
||||
/// </summary>
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
22
CaddyManager/Models/Caddy/CaddySaveConfigurationRequest.cs
Normal file
22
CaddyManager/Models/Caddy/CaddySaveConfigurationRequest.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace CaddyManager.Models.Caddy;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps the information needed to save a Caddy configuration
|
||||
/// </summary>
|
||||
public class CaddySaveConfigurationRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates if the configuration is new
|
||||
/// </summary>
|
||||
public bool IsNew { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Caddy configuration file
|
||||
/// </summary>
|
||||
public required string FileName { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Content of the Caddy configuration file
|
||||
/// </summary>
|
||||
public string Content { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -15,6 +15,15 @@ builder.Services.RegisterAssemblyPublicNonGenericClasses()
|
||||
.Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository"))
|
||||
.AsPublicImplementedInterfaces();
|
||||
|
||||
builder.Services.AddSignalR(e => { e.MaximumReceiveMessageSize = 102400000; });
|
||||
|
||||
builder.Services.AddMudServices(config =>
|
||||
{
|
||||
config.SnackbarConfiguration.VisibleStateDuration = 4000;
|
||||
config.SnackbarConfiguration.HideTransitionDuration = 100;
|
||||
config.SnackbarConfiguration.ShowTransitionDuration = 100;
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using CaddyManager.Configurations.Caddy;
|
||||
using CaddyManager.Contracts.Caddy;
|
||||
using CaddyManager.Contracts.Configurations;
|
||||
using CaddyManager.Models.Caddy;
|
||||
|
||||
namespace CaddyManager.Services;
|
||||
|
||||
@@ -10,10 +11,10 @@ public class CaddyService(IConfigurationsService configurationsService) : ICaddy
|
||||
/// <summary>
|
||||
/// File name of the global configuration Caddyfile
|
||||
/// </summary>
|
||||
public const string CaddyGlobalConfigName = "Caddyfile";
|
||||
|
||||
private const string CaddyGlobalConfigName = "Caddyfile";
|
||||
|
||||
private CaddyServiceConfigurations Configurations => configurationsService.CaddyServiceConfigurations;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<string> GetExistingCaddyConfigurations()
|
||||
{
|
||||
@@ -26,18 +27,69 @@ public class CaddyService(IConfigurationsService configurationsService) : ICaddy
|
||||
/// <inheritdoc />
|
||||
public string GetCaddyConfigurationContent(string configurationName)
|
||||
{
|
||||
var path = configurationName == CaddyGlobalConfigName
|
||||
? Path.Combine(Configurations.ConfigDir, CaddyGlobalConfigName)
|
||||
var path = configurationName == CaddyGlobalConfigName
|
||||
? Path.Combine(Configurations.ConfigDir, CaddyGlobalConfigName)
|
||||
: Path.Combine(Configurations.ConfigDir, $"{configurationName}.caddy");
|
||||
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return File.ReadAllText(path);
|
||||
}
|
||||
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetCaddyGlobalConfigurationContent() => GetCaddyConfigurationContent(CaddyGlobalConfigName);
|
||||
|
||||
/// <inheritdoc />
|
||||
public CaddyOperationResponse SaveCaddyConfiguration(CaddySaveConfigurationRequest request)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.FileName))
|
||||
{
|
||||
return new CaddyOperationResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "The configuration file name is required"
|
||||
};
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(Configurations.ConfigDir,
|
||||
request.FileName == CaddyGlobalConfigName ? CaddyGlobalConfigName : $"{request.FileName}.caddy");
|
||||
// if in the new mode, we would have to check if the file already exists
|
||||
if (request.IsNew && File.Exists(filePath))
|
||||
{
|
||||
return new CaddyOperationResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "The configuration file already exists"
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(filePath, request.Content);
|
||||
return new CaddyOperationResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "Configuration file saved successfully"
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new CaddyOperationResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CaddyOperationResponse SaveCaddyGlobalConfiguration(string content) => SaveCaddyConfiguration(
|
||||
new CaddySaveConfigurationRequest
|
||||
{
|
||||
FileName = CaddyGlobalConfigName,
|
||||
Content = content
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user