feat: save caddy file on edit and add new
This commit is contained in:
@@ -21,7 +21,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Models\" />
|
|
||||||
<Folder Include="Repositories\" />
|
<Folder Include="Repositories\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
<script src="_content/BlazorMonaco/jsInterop.js"></script>
|
<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/loader.js"></script>
|
||||||
<script src="_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.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="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||||
|
<script src="_framework/blazor.web.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
@attribute [StreamRendering]
|
@attribute [StreamRendering]
|
||||||
@using CaddyManager.Contracts.Caddy
|
|
||||||
@inject ICaddyService CaddyService
|
|
||||||
|
|
||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -9,7 +7,8 @@
|
|||||||
ShrinkLabel="true"
|
ShrinkLabel="true"
|
||||||
Disabled="@(!IsNew)"></MudTextField>
|
Disabled="@(!IsNew)"></MudTextField>
|
||||||
<MudText Typo="Typo.caption" Style="padding-left: 18px; padding-bottom: 8px;">File content</MudText>
|
<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>
|
CssClass="caddy-file-editor"></StandaloneCodeEditor>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using BlazorMonaco.Editor;
|
using BlazorMonaco.Editor;
|
||||||
using CaddyManager.Contracts.Caddy;
|
using CaddyManager.Contracts.Caddy;
|
||||||
|
using CaddyManager.Models.Caddy;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
|
||||||
@@ -8,17 +9,20 @@ namespace CaddyManager.Components.Pages.CaddyfileEditor;
|
|||||||
public partial class CaddyfileEditor : ComponentBase
|
public partial class CaddyfileEditor : ComponentBase
|
||||||
{
|
{
|
||||||
private string _caddyConfigurationContent = string.Empty;
|
private string _caddyConfigurationContent = string.Empty;
|
||||||
|
private StandaloneCodeEditor _codeEditor = null!;
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the Caddy configuration file is new
|
/// Determines if the Caddy configuration file is new
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool IsNew { get; set; }
|
private bool IsNew { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter] public string FileName { get; set; } = string.Empty;
|
||||||
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()
|
protected override Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@@ -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();
|
private void Cancel() => MudDialog.Cancel();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
@page "/caddyfile"
|
@page "/caddyfile"
|
||||||
@attribute [StreamRendering]
|
@attribute [StreamRendering]
|
||||||
@using CaddyManager.Contracts.Caddy
|
|
||||||
@inject ICaddyService CaddyService
|
|
||||||
|
|
||||||
<PageTitle>Global Caddyfile</PageTitle>
|
<PageTitle>Global Caddyfile</PageTitle>
|
||||||
|
|
||||||
@@ -12,7 +10,9 @@
|
|||||||
</MudText>
|
</MudText>
|
||||||
</MudCardHeader>
|
</MudCardHeader>
|
||||||
<MudCardContent>
|
<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/>
|
<MudDivider/>
|
||||||
</MudCardContent>
|
</MudCardContent>
|
||||||
<MudCardActions>
|
<MudCardActions>
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
using BlazorMonaco.Editor;
|
using BlazorMonaco.Editor;
|
||||||
|
using CaddyManager.Contracts.Caddy;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MudBlazor;
|
||||||
|
|
||||||
namespace CaddyManager.Components.Pages;
|
namespace CaddyManager.Components.Pages;
|
||||||
|
|
||||||
public partial class Caddyfile: ComponentBase
|
public partial class CaddyfilePage : ComponentBase
|
||||||
{
|
{
|
||||||
private string _caddyConfigurationContent = string.Empty;
|
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()
|
protected override Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@@ -24,9 +31,18 @@ public partial class Caddyfile: ComponentBase
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
private void Cancel()
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@attribute [StreamRendering]
|
@attribute [StreamRendering]
|
||||||
@using CaddyManager.Contracts.Caddy
|
|
||||||
@inject ICaddyService CaddyService
|
|
||||||
@inject IDialogService DialogService
|
|
||||||
|
|
||||||
<PageTitle>Reverse proxy configurations</PageTitle>
|
<PageTitle>Reverse proxy configurations</PageTitle>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using CaddyManager.Contracts.Caddy;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
|
||||||
@@ -8,19 +9,27 @@ public partial class ReverseProxiesPage : ComponentBase
|
|||||||
private List<string> _availableCaddyConfigurations = [];
|
private List<string> _availableCaddyConfigurations = [];
|
||||||
private IReadOnlyCollection<string> _selectedCaddyConfigurations = [];
|
private IReadOnlyCollection<string> _selectedCaddyConfigurations = [];
|
||||||
|
|
||||||
protected override Task OnInitializedAsync()
|
[Inject]
|
||||||
|
private ICaddyService CaddyService { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IDialogService DialogService { get; set; } = null!;
|
||||||
|
|
||||||
|
protected override void OnAfterRender(bool firstRender)
|
||||||
{
|
{
|
||||||
_availableCaddyConfigurations = CaddyService.GetExistingCaddyConfigurations();
|
if (firstRender)
|
||||||
return base.OnInitializedAsync();
|
{
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method to help open the dialog to create a new reverse proxy configuration
|
/// Method to help open the dialog to create a new reverse proxy configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <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
|
options: new DialogOptions
|
||||||
{
|
{
|
||||||
FullWidth = true,
|
FullWidth = true,
|
||||||
@@ -29,5 +38,21 @@ public partial class ReverseProxiesPage : ComponentBase
|
|||||||
{
|
{
|
||||||
{ "FileName", string.Empty }
|
{ "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]
|
@attribute [StreamRendering]
|
||||||
@inject ICaddyService CaddyService
|
|
||||||
@inject IDialogService DialogService
|
|
||||||
|
|
||||||
<MudListItem T="string" Text="@FileName" OnClick="Edit" OnClickPreventDefault="true">
|
<MudListItem T="string" Text="@FileName" OnClick="Edit" OnClickPreventDefault="true">
|
||||||
<MudContainer Class="d-flex flex-row flex-grow-1 gap-4">
|
<MudContainer Class="d-flex flex-row flex-grow-1 gap-4">
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using CaddyManager.Contracts.Caddy;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
|
||||||
@@ -11,6 +12,12 @@ public partial class ReverseProxyItem : ComponentBase
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string FileName { get; set; } = string.Empty;
|
public string FileName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IDialogService DialogService { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private ICaddyService CaddyService { get; set; } = null!;
|
||||||
|
|
||||||
private Task Edit()
|
private Task Edit()
|
||||||
{
|
{
|
||||||
return DialogService.ShowAsync<CaddyfileEditor.CaddyfileEditor>("Caddy file", options: new DialogOptions
|
return DialogService.ShowAsync<CaddyfileEditor.CaddyfileEditor>("Caddy file", options: new DialogOptions
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using CaddyManager.Models.Caddy;
|
||||||
|
|
||||||
namespace CaddyManager.Contracts.Caddy;
|
namespace CaddyManager.Contracts.Caddy;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -24,4 +26,18 @@ public interface ICaddyService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string GetCaddyGlobalConfigurationContent();
|
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"))
|
.Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository"))
|
||||||
.AsPublicImplementedInterfaces();
|
.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();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using CaddyManager.Configurations.Caddy;
|
using CaddyManager.Configurations.Caddy;
|
||||||
using CaddyManager.Contracts.Caddy;
|
using CaddyManager.Contracts.Caddy;
|
||||||
using CaddyManager.Contracts.Configurations;
|
using CaddyManager.Contracts.Configurations;
|
||||||
|
using CaddyManager.Models.Caddy;
|
||||||
|
|
||||||
namespace CaddyManager.Services;
|
namespace CaddyManager.Services;
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ public class CaddyService(IConfigurationsService configurationsService) : ICaddy
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// File name of the global configuration Caddyfile
|
/// File name of the global configuration Caddyfile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string CaddyGlobalConfigName = "Caddyfile";
|
private const string CaddyGlobalConfigName = "Caddyfile";
|
||||||
|
|
||||||
private CaddyServiceConfigurations Configurations => configurationsService.CaddyServiceConfigurations;
|
private CaddyServiceConfigurations Configurations => configurationsService.CaddyServiceConfigurations;
|
||||||
|
|
||||||
@@ -40,4 +41,55 @@ public class CaddyService(IConfigurationsService configurationsService) : ICaddy
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCaddyGlobalConfigurationContent() => GetCaddyConfigurationContent(CaddyGlobalConfigName);
|
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