Continuing building

This commit is contained in:
Eugene ;) 2020-07-06 18:01:01 +02:00
parent 73a6125faf
commit 20a4a9ebbf
17 changed files with 416 additions and 252 deletions

View File

@ -27,4 +27,21 @@ namespace Seenginx.Models
public void SetData(D data) => Data = data;
}
public class Result
{
public bool AllOk { get; private set; } = true;
public string ErrorMessage { get; private set; }
public Exception Exception { get; private set; } = null;
public Result Invalidate(string errorMessage, Exception exception = null)
{
AllOk = false;
ErrorMessage = errorMessage;
if (exception != null)
Exception = exception;
return this;
}
}
}

View File

@ -7,7 +7,7 @@
<div class="control has-icons-left is-expanded">
<input formnovalidate @oninput="e => SearchInputChanged(e.Value.ToString())" @bind-value="SearchInput" class="input is-rounded is-small neoInput" type="text" placeholder="Search...">
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-search-outline"></i>
<i class="mdi mdi-file-search"></i>
</span>
</div>
</div>
@ -17,33 +17,39 @@
@if (IsAnyFileSelected)
{
<div class="field is-grouped">
<div class="control is-expanded borderRBig neoInput has-text-centered has-icons-left">
<input class="input is-5 is-rounded is-small neoInput" type="text" placeholder="Search..."
disabled="@(SelectedFile.CanBeDeleted ? null : "disabled")" @bind-value="SelectedFile.Name">
<span class="icon is-small is-left @(ConfigHasChanged ? "has-text-danger" : "has-text-dark")">
<i class="mdi @(ConfigHasChanged ? "mdi-not-equal" : "mdi-equal")"></i>
</span>
<div class="control is-expanded borderRBig neomorphXSmall has-icons-left has-text-centered">
<span>@SelectedFile.Name</span>
</div>
<div class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileRenameClick">
<p class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileRenameClick" title="Rename configuration">
<span class="icon is-medium">
<i class="mdi mdi-pencil-outline"></i>
<i class="mdi mdi-pencil"></i>
</span>
</button>
</div>
<div class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileCloseClick">
</p>
@if (!string.IsNullOrEmpty(SelectedFile.DraftBody))
{
<p class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnLoadDraftClick" title="Load draft">
<span class="icon is-medium">
<i class="mdi mdi-content-save-edit"></i>
</span>
</button>
</p>
}
<p class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileCloseClick" title="Close">
<span class="icon is-medium">
<i class="mdi mdi-close"></i>
</span>
</button>
</div>
</p>
</div>
}
else
{
<div class="field">
<div class="control is-expanded borderRBig neoInput has-text-centered"><span>···</span></div>
<div class="control is-expanded borderRBig neomorphXSmall has-text-centered"><span>···</span></div>
</div>
}
</div>
@ -52,8 +58,8 @@
<div class="filesList">
@foreach (var file in Files)
{
<div @onclick="async e => await OnFileClick(e,file)" title="@(string.IsNullOrEmpty(file.Folder) ? $"/{file.Name}" : $"/{file.Folder}/{file.Name}")" @key="file" class="confFile borderRSmall isFinger neoFile @file.IsVisible @file.IsSelected">
<p class="has-text-weight-bold ellipsis"><span class="icon @(file.CanBeDeleted ? null : "has-text-danger")"><i class="mdi mdi-file-cog-outline"></i></span> @file.Name</p>
<div @onclick="async e => await OnFileClick(e,file)" title="@file.FullPath" @key="file" class="confFile borderRSmall isFinger neoFile @file.IsVisible @file.IsSelected">
<p class="has-text-weight-bold ellipsis"><span class="icon @(file.CanBeDeleted ? null : "has-text-danger")"><i class="mdi mdi-file-cog"></i></span> @file.Name</p>
</div>
}
</div>
@ -91,10 +97,10 @@
<button @onclick="OnUndoChanges" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-dark"><i class="mdi mdi-undo-variant"></i></span> <span>Undo changes</span></button>
@if (HasTesting)
{
<button @onclick="OnTest" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-danger"><i class="mdi mdi-alert-outline"></i></span> <span>Test</span></button>
<button @onclick="OnTest" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-danger"><i class="mdi mdi-alert"></i></span> <span>Test</span></button>
}
<button @onclick="OnSaveDraft" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-light"><i class="mdi mdi-content-save-outline"></i></span> <span>@(string.IsNullOrEmpty(SelectedFile.DraftBody) ? "Create" : "Save") draft</span></button>
<button @onclick="OnSave" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-success"><i class="mdi mdi-content-save-all-outline"></i></span> <span>Save</span></button>
<button @onclick="OnSaveDraft" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-light"><i class="mdi mdi-content-save"></i></span> <span>@(string.IsNullOrEmpty(SelectedFile.DraftBody) ? "Create" : "Save") draft</span></button>
<button @onclick="OnSave" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-success"><i class="mdi mdi-content-save-all"></i></span> <span>Save</span></button>
</div>
}
else

View File

@ -33,7 +33,6 @@ namespace Seenginx.Components
[Parameter] public CFile SelectedFile { get; set; } = default;
protected string SearchInput { get; set; }
private bool ConfigHasChanged => (string.IsNullOrEmpty(SelectedFile.DraftBody) ? false : SelectedFile.Body != SelectedFile.DraftBody);
protected bool IsAnyFileSelected => SelectedFile != default;
protected string IsSelectedFileDeletable
@ -90,6 +89,11 @@ namespace Seenginx.Components
await RenameFileCallback.InvokeAsync(null);
}
protected async Task OnLoadDraftClick(MouseEventArgs e)
{
await JsRuntime.InvokeVoidAsync("UpdateEditor", SelectedFile.DraftBody);
}
protected async Task OnFileCloseClick(MouseEventArgs e)
{
Files.ForEach(f => f.Deselect());

View File

@ -1,7 +1,8 @@
@inherits NginxBase
@page "/nginx"
<FilesWithEditor CFile="ConfigFile" Files="ConfigFiles" SelectedFile="SelectedFile" SelectedFileChanged="SelectedFileChanged"
TestConfiguration="TestConfiguration" DeleteFileCallback="DeleteFile" ShowAddFileModal="ShowAddFileModal"
TestConfiguration="TestConfiguration" DeleteFileCallback="DeleteFile" ShowAddFileModal="AddFileModal"
RenameFileCallback="RenameFileModal"
HasTesting="true" SaveFileCallback="SaveFileAsync" SaveDraftFileCallback="SaveDraftFileAsync">
</FilesWithEditor>

View File

@ -17,7 +17,6 @@ namespace Seenginx.Pages
public class NginxBase : ComponentBase
{
[Inject] public INginxService NginxService { get; set; }
[Inject] public IFileManager FileService { get; set; }
[Inject] public IModalService Modal { get; set; }
public string InputSearch { get; set; }
@ -47,7 +46,7 @@ namespace Seenginx.Pages
SelectedFile = configFile;
}
public async Task ShowAddFileModal()
public async Task AddFileModal()
{
var parameters = new ModalParameters();
parameters.Add(nameof(Templates), Templates);
@ -57,7 +56,7 @@ namespace Seenginx.Pages
if (result.Cancelled) return;
var validationResult = await NginxService.ValidateNewConfigurationAsync((NewFileForm)result.Data);
var validationResult = await NginxService.ValidateForAddFileAsync((NewFileForm)result.Data);
if (!validationResult.AllOk)
{
@ -77,14 +76,70 @@ namespace Seenginx.Pages
SelectedFile.Select();
}
public async Task RenameFileModal()
{
var parameters = new ModalParameters();
parameters.Add(nameof(RenameForm.Name), SelectedFile.Name);
var resultAwait = Modal.Show<RenameForm>(string.Empty, parameters);
var result = await resultAwait.Result;
if (result.Cancelled) return;
var validationResult = await NginxService.ValidateForRenameFileAsync(ConfigFiles, SelectedFile, result.Data.ToString());
if (!validationResult.AllOk)
{
var popupAwait = Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, validationResult.ErrorMessage));
await popupAwait.Result;
return;
}
var renameResult = await NginxService.RenameFileAsync(SelectedFile, $"{result.Data}.conf");
if (!renameResult.AllOk)
{
var popupAwait = Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, renameResult.ErrorMessage));
await popupAwait.Result;
return;
}
SelectedFile.Name = result.Data.ToString();
}
public async Task SaveFileAsync()
{
var saveUpdateResult = await FileService.SaveFileAsync(SelectedFile);
var validationResult = await NginxService.ValidateForSaveFileAsync(SelectedFile);
if (!validationResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, validationResult.ErrorMessage)).Result;
return;
}
var saveResult = await NginxService.SaveFileAsync(SelectedFile);
if (!saveResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, saveResult.ErrorMessage)).Result;
return;
}
}
public async Task SaveDraftFileAsync()
{
var saveUpdateDraftResult = await FileService.SaveDraftFileAsync(SelectedFile);
var validationResult = await NginxService.ValidateForSaveDraftFileAsync(SelectedFile);
if (!validationResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, validationResult.ErrorMessage)).Result;
return;
}
var saveDraftResult = await NginxService.SaveDraftFileAsync(SelectedFile);
if (!saveDraftResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, saveDraftResult.ErrorMessage)).Result;
return;
}
}
public async Task TestConfiguration()

View File

@ -104,6 +104,12 @@
border: none !important;
transform: scale(1.1);
}
&Plain {
box-shadow: -2px -2px 4px rgba($light-shadow, .5), 2px 2px 4px rgba($dark-shadow, .5);
background: none !important;
border: none !important;
}
}
}

View File

@ -1,83 +0,0 @@
using Seenginx.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Seenginx.Services
{
public class FileManager : IFileManager
{
public async Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile)
{
var result = new Result<ConfigFile>(configFile);
try
{
var validationResult = ValidForUpdate(configFile);
if (!validationResult.AllOk)
return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}");
await File.WriteAllTextAsync(configFile.FullPath, configFile.Body);
return result;
}
catch (Exception ex)
{
return result.Invalidate($"Exception at {nameof(SaveFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
}
}
public async Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile)
{
var result = new Result<ConfigFile>(configFile);
try
{
var validationResult = ValidForUpdate(configFile);
if (!validationResult.AllOk)
return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}");
await File.WriteAllTextAsync($"{configFile.FullPath}.draft", configFile.DraftBody);
return result;
}
catch (Exception ex)
{
return result.Invalidate($"Exception at {nameof(SaveDraftFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
}
}
public Result<bool> DeleteFile(ConfigFile configFile)
{
var result = new Result<bool>();
try
{
var validationResult = ValidForUpdate(configFile);
if (!validationResult.AllOk)
return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}");
File.Delete(configFile.FullPath);
if (File.Exists($"{configFile.FullPath}.draft"))
File.Delete($"{configFile.FullPath}.draft");
return result;
}
catch (Exception ex)
{
return result.Invalidate($"Exception at {nameof(DeleteFile)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
}
}
private Result<string> ValidForUpdate(ConfigFile configFile)
{
var result = new Result<string>();
if (!Directory.Exists(Directory.GetDirectoryRoot(configFile.FullPath)))
return result.Invalidate($"Directory '{Directory.GetDirectoryRoot(configFile.FullPath)}' doesn't exist.");
if (!File.Exists(configFile.FullPath))
return result.Invalidate($"File '{configFile.FullPath}' doesn't exist.");
return result;
}
}
}

View File

@ -1,15 +0,0 @@
using Seenginx.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Seenginx.Services
{
public interface IFileManager
{
Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile);
Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile);
Result<bool> DeleteFile(ConfigFile configFile);
}
}

View File

@ -8,12 +8,22 @@ namespace Seenginx.Services
{
Task<IEnumerable<ConfigFile>> GetFilesAsync();
Task<IEnumerable<Template>> GetTemplates();
Task<Result<string>> TestFileAsync(ConfigFile configFile);
Task<Result> ValidateForAddFileAsync(NewFileForm newFileForm);
Task<Result<ConfigFile>> AddFileAsync(NewFileForm newFileForm);
Task<Result> ValidateForSaveFileAsync(ConfigFile configFile);
Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile);
Task<Result> ValidateForSaveDraftFileAsync(ConfigFile configFile);
Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile);
Task<Result<bool>> RenameFileAsync(ConfigFile configFile);
Task<Result<bool>> DeleteFileAsync(ConfigFile configFile);
Task<Result<bool>> ValidateNewConfigurationAsync(NewFileForm newFileForm);
Task<Result> ValidateForRenameFileAsync(List<ConfigFile> configFiles, ConfigFile configFile, string newName);
Task<Result> RenameFileAsync(ConfigFile configFile, string newName);
Task<Result> ValidateForDeleteFileAsync(ConfigFile configFile);
Task<Result> DeleteFileAsync(ConfigFile configFile);
}
}

View File

@ -20,110 +20,6 @@ namespace Seenginx.Services
ConfigPaths = configPaths;
}
public async Task<Result<bool>> ValidateNewConfigurationAsync(NewFileForm newFileForm)
{
var validationResult = new Result<bool>();
try
{
var filePath = Path.Combine(ConfigPaths.NginxPath, "conf.d", $"{newFileForm.Name}.conf");
if (File.Exists(filePath))
return validationResult.Invalidate($"There's already a file with the '{newFileForm.Name}.conf' name.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate($"Exception at {nameof(ValidateNewConfigurationAsync)}()", ex);
}
}
public async Task<Result<ConfigFile>> AddFileAsync(NewFileForm newFileForm)
{
var addResult = new Result<ConfigFile>();
try
{
var newFile = new ConfigFile();
newFile.Name = $"{newFileForm.Name}.conf";
newFile.Folder = "/conf.d";
newFile.FullPath = Path.Combine(ConfigPaths.NginxPath, "conf.d", newFile.Name);
newFile.Body = newFileForm.SelectedTemplate == 0.ToString() ? string.Empty : (await GetTemplates()).SingleOrDefault(t => t.Name == newFileForm.SelectedTemplate)?.Code;
newFile.LastUpdated = DateTime.UtcNow;
newFile.DraftBody = newFile.Body;
await File.WriteAllTextAsync(newFile.FullPath, newFile.Body, Encoding.UTF8);
addResult.SetData(newFile);
return addResult;
}
catch (Exception ex)
{
return addResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<bool>> DeleteFileAsync(ConfigFile configFile)
{
var result = new Result<bool>(true);
try
{
if (!File.Exists(configFile.FullPath))
return result.Invalidate($"File '{configFile.FullPath}' not found.");
File.Delete(configFile.FullPath);
return result;
}
catch (Exception ex)
{
return result.Invalidate(ex.Message, ex);
}
}
public async Task<Result<string>> TestFileAsync(ConfigFile configFile)
{
await Task.Run(() => { });
var result = new Result<string>();
result.SetData("Uhu");
return result;
}
public async Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile)
{
var saveResult = new Result<ConfigFile>();
try
{
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name), configFile.Body, Encoding.UTF8);
return saveResult;
}
catch (Exception ex)
{
return saveResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile)
{
var saveDraftResult = new Result<ConfigFile>();
try
{
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.draft"), configFile.DraftBody, Encoding.UTF8);
return saveDraftResult;
}
catch (Exception ex)
{
return saveDraftResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<bool>> RenameFileAsync(ConfigFile configFile, string newName)
{
File.Move()
}
public async Task<IEnumerable<ConfigFile>> GetFilesAsync()
{
await Task.Run(() => { });
@ -138,28 +34,28 @@ namespace Seenginx.Services
var rootConfigFiles = rootConfigs.Select(fp =>
{
var fileName = Path.GetFileName(fp);
var name = Path.GetFileNameWithoutExtension(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = false;
configFile.Folder = string.Empty;
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Name);
configFile.Name = name;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, $"{configFile.Name}.conf");
configFile.Body = File.ReadAllText(fp);
if (rootDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(rootDraftConfigs.First(cfp => cfp.Contains(fileName)));
if (rootDraftConfigs.Any(cfp => cfp.Contains(name)))
configFile.DraftBody = File.ReadAllText(rootDraftConfigs.First(cfp => cfp.Contains(name)));
return configFile;
});
var confdConfigFiles = confdConfigs.Select(fp =>
{
var fileName = Path.GetFileName(fp);
var fileName = Path.GetFileNameWithoutExtension(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = true;
configFile.Folder = "conf.d";
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf");
configFile.Body = File.ReadAllText(fp);
if (confDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
@ -168,13 +64,13 @@ namespace Seenginx.Services
});
var sitesAvailableConfigFiles = sitesAvailableConfigs.Select(fp =>
{
var fileName = Path.GetFileName(fp);
var fileName = Path.GetFileNameWithoutExtension(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = true;
configFile.Folder = "sites-available";
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf");
configFile.Body = File.ReadAllText(fp);
if (sitesAvailableDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(sitesAvailableDraftConfigs.First(cfp => cfp.Contains(fileName)));
@ -237,11 +133,209 @@ namespace Seenginx.Services
}
public async Task<Result> ValidateForAddFileAsync(NewFileForm newFileForm)
{
var validationResult = new Result();
try
{
var filePath = Path.Combine(ConfigPaths.NginxPath, "conf.d", $"{newFileForm.Name}.conf");
if (File.Exists(filePath))
return validationResult.Invalidate($"There's already a file with the '{newFileForm.Name}.conf' name.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate($"Exception at {nameof(ValidateForAddFileAsync)}()", ex);
}
}
public async Task<Result<ConfigFile>> AddFileAsync(NewFileForm newFileForm)
{
var addResult = new Result<ConfigFile>();
try
{
var newFile = new ConfigFile();
newFile.Name = $"{newFileForm.Name}.conf";
newFile.Folder = "conf.d";
newFile.FullPath = Path.Combine(ConfigPaths.NginxPath, newFile.Folder, newFile.Name);
newFile.Body = newFileForm.SelectedTemplate == 0.ToString() ? string.Empty : (await GetTemplates()).SingleOrDefault(t => t.Name == newFileForm.SelectedTemplate)?.Code;
newFile.LastUpdated = DateTime.UtcNow;
await File.WriteAllTextAsync(newFile.FullPath, newFile.Body, Encoding.UTF8);
addResult.SetData(newFile);
return addResult;
}
catch (Exception ex)
{
return addResult.Invalidate(ex.Message, ex);
}
}
//public async Task<Result<bool>> DeleteFileAsync(ConfigFile configFile)
public async Task<Result> ValidateForDeleteFileAsync(ConfigFile configFile)
{
var validationResult = new Result();
try
{
if (File.Exists(configFile.FullPath))
return validationResult.Invalidate($"File '{configFile.FullPath}' not found.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result> DeleteFileAsync(ConfigFile configFile)
{
var result = new Result();
try
{
if (!File.Exists(configFile.FullPath))
return result.Invalidate($"File '{configFile.FullPath}' not found.");
File.Delete(configFile.FullPath);
return result;
}
catch (Exception ex)
{
return result.Invalidate(ex.Message, ex);
}
}
public async Task<Result> ValidateForSaveFileAsync(ConfigFile configFile)
{
var validationResult = new Result();
try
{
if (File.Exists(configFile.FullPath))
return validationResult.Invalidate($"File '{configFile.FullPath}' not found.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile)
{
var saveResult = new Result<ConfigFile>();
try
{
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf"), configFile.Body, Encoding.UTF8);
return saveResult;
}
catch (Exception ex)
{
return saveResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result> ValidateForSaveDraftFileAsync(ConfigFile configFile)
{
var validationResult = new Result();
try
{
var draftPathName = $"{configFile.FullPath}.draft";
if (File.Exists(draftPathName))
return validationResult.Invalidate($"File '{draftPathName}' not found.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile)
{
var saveDraftResult = new Result<ConfigFile>();
try
{
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf.draft"), configFile.DraftBody, Encoding.UTF8);
return saveDraftResult;
}
catch (Exception ex)
{
return saveDraftResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result> ValidateForRenameFileAsync(List<ConfigFile> configFiles, ConfigFile selectedConfigFile, string newName)
{
var renameResult = new Result();
try
{
if(configFiles.Count(cf => cf.Name == newName) > 0)
return renameResult.Invalidate($"File '{selectedConfigFile.FullPath}' already exists.");
if (File.Exists(selectedConfigFile.FullPath))
return renameResult.Invalidate($"Original file '{selectedConfigFile.FullPath}' not found.");
var newPathName = Path.Combine(ConfigPaths.NginxPath, selectedConfigFile.Folder, $"{newName}.conf");
if (File.Exists(newPathName))
return renameResult.Invalidate($"The file '{newPathName}' already exists.");
return renameResult;
}
catch (Exception ex)
{
return renameResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result> RenameFileAsync(ConfigFile configFile, string newName)
{
var renameResult = new Result();
try
{
var originalPathName = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf");
var newPathName = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, newName);
File.Move(originalPathName, newPathName, overwrite: false);
return renameResult;
}
catch (Exception ex)
{
return renameResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<string>> TestFileAsync(ConfigFile configFile)
{
await Task.Run(() => { });
var result = new Result<string>();
result.SetData("Uhu");
return result;
}
//public async Task<Result> DeleteFileAsync(ConfigFile configFile)
//{
// var result = new Result<bool>(true);
// var result = new Result(true);
// try
// {
// return result;

View File

@ -17,7 +17,7 @@
@key="@ActiveNav.Keys.ElementAt(0)"
ActiveClass="@ActiveNav.GetValueOrDefault("nginx")"
@onclick="@(e => SelectMenuItem("nginx"))">
<span class="mdi mdi-file-cog-outline"></span>
<span class="mdi mdi-file-cog"></span>
Configuration
</NavLink>
</li>
@ -26,7 +26,7 @@
@key="@ActiveNav.Keys.ElementAt(1)"
ActiveClass="@ActiveNav.GetValueOrDefault("nginxlogs")"
@onclick="@(e => SelectMenuItem("nginxlogs"))">
<span class="mdi mdi-information-outline"></span>
<span class="mdi mdi-information"></span>
Logs
</NavLink>
</li>
@ -41,7 +41,7 @@
@key="@ActiveNav.Keys.ElementAt(2)"
ActiveClass="@ActiveNav.GetValueOrDefault("systemd")"
@onclick="@(e => SelectMenuItem("systemd"))">
<span class="mdi mdi-file-cog-outline"></span>
<span class="mdi mdi-file-cog"></span>
Configuration
</NavLink>
</li>
@ -50,7 +50,7 @@
@key="@ActiveNav.Keys.ElementAt(3)"
ActiveClass="@ActiveNav.GetValueOrDefault("systemdlogs")"
@onclick="@(e => SelectMenuItem("systemdlogs"))">
<span class="mdi mdi-information-outline"></span>
<span class="mdi mdi-information"></span>
Logs
</NavLink>
</li>
@ -65,7 +65,7 @@
@key="@ActiveNav.Keys.ElementAt(4)"
ActiveClass="@ActiveNav.GetValueOrDefault("dmesg")"
@onclick="@(e => SelectMenuItem("dmesg"))">
<span class="mdi mdi-information-outline"></span>
<span class="mdi mdi-information"></span>
Logs
</NavLink>
</li>

View File

@ -21,7 +21,7 @@
</select>
</div>
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-puzzle-outline"></i>
<i class="mdi mdi-puzzle"></i>
</span>
</div>
<p class="help">Any template to quick setup the configuration</p>
@ -32,7 +32,7 @@
<div class="control has-icons-left">
<input class="input is-rounded is-small neoInput" type="text" placeholder="Name" @bind="TemplateName">
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-code-outline"></i>
<i class="mdi mdi-file-code"></i>
</span>
</div>
<p class="help">Name it the same as the service which is going to run behind</p>

View File

@ -0,0 +1,65 @@
<div class="modal-content neomorph">
<div class="modal-card-head">
<h4 class="modal-card-title has-text-centered">
Change the configuration name
</h4>
</div>
<div class="modal-card-body">
<EditForm Model="Name">
<div class="field">
<label class="label">New configuration name</label>
<div class="control has-icons-left">
<input class="input is-rounded is-small neoInput" type="text" placeholder="Name" @bind="Name">
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-code"></i>
</span>
</div>
<DataAnnotationsValidator />
<p class="help">Give a name coherently to the service which is going to run behind</p>
</div>
</EditForm>
</div>
<div class="modal-card-foot">
<div class="level fullwidth">
<div class="level-left">
<div class="level-item">
<button type="button" class="button is-rounded neoBtnSmall is-small has-text-dark" @onclick="Cancel">
<span class="icon is-small">
<i class="mdi mdi-close"></i>
</span>
<span>Close</span>
</button>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button type="submit" class="button is-primary is-rounded neoBtnSmall is-small has-text-dark" @onclick="SubmitForm">
<span class="icon is-small">
<i class="mdi mdi-pen"></i>
</span>
<span>Rename</span>
</button>
</div>
</div>
</div>
</div>
</div>
@code {
[CascadingParameter]
BlazoredModalInstance BlazoredModal { get; set; }
[Required, Parameter, MaxLength(251)]
public string Name { get; set; }
void SubmitForm() => BlazoredModal.Close(ModalResult.Ok(Name));
void Cancel() => BlazoredModal.Cancel();
}

View File

@ -48,7 +48,6 @@ namespace Seenginx
services.AddTransient<IDmesgService, DmesgService>();
services.AddTransient<INginxService, NginxService>();
services.AddTransient<ISystemDService, SystemDService>();
services.AddTransient<IFileManager, FileManager>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

File diff suppressed because one or more lines are too long

View File

@ -106,6 +106,10 @@ html {
background: none !important;
border: none !important;
transform: scale(1.1); }
.neoBtnSmallPlain {
box-shadow: -2px -2px 4px rgba(251, 238, 208, 0.5), 2px 2px 4px rgba(241, 185, 65, 0.5);
background: none !important;
border: none !important; }
.neoFile {
box-shadow: 0px 0px 0px rgba(251, 238, 208, 0.5), 0px 0px 0px rgba(241, 185, 65, 0.5) !important;

File diff suppressed because one or more lines are too long