More development
This commit is contained in:
parent
c1f5f82329
commit
29cde263d3
@ -6,18 +6,19 @@ namespace Seenginx.Models
|
||||
{
|
||||
public class ConfigFile
|
||||
{
|
||||
public string FullPath { get; set; }
|
||||
public string Folder { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool HasDraft => !string.IsNullOrEmpty(DraftName);
|
||||
public string DraftName { get; set; }
|
||||
public string OriginalBody { get; set; }
|
||||
public string Body { get; set; }
|
||||
public string DraftBody { get; set; }
|
||||
public string Permissions { get; set; }
|
||||
public DateTime LastUpdated { get; set; }
|
||||
public string[] Owners { get; set; }
|
||||
public string Permissions { get; set; }
|
||||
public bool CanBeDeleted { get; set; } = true;
|
||||
public string IsVisible { get; set; } = string.Empty;
|
||||
public string IsSelected { get; set; } = string.Empty;
|
||||
public bool HasDraft => !string.IsNullOrEmpty(DraftName);
|
||||
public bool CanBeDeleted { get; set; } = true;
|
||||
|
||||
public void Hide() { IsVisible = "is-hidden"; }
|
||||
public void Unhide() { IsVisible = string.Empty; }
|
||||
|
@ -11,6 +11,12 @@ namespace Seenginx.Models
|
||||
public Exception Exception { get; private set; } = null;
|
||||
public D Data { get; private set; }
|
||||
|
||||
public Result() { }
|
||||
public Result(D data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public Result<D> Invalidate(string errorMessage, Exception exception = null)
|
||||
{
|
||||
AllOk = false;
|
||||
|
@ -1,15 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Seenginx.Models
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string Summary { get; set; }
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
<div class="control has-icons-left">
|
||||
<div class="select is-small is-rounded">
|
||||
<select class="neoInput" @onchange="e => OnFilterClick(e.Value.ToString())">
|
||||
<select class="neoBtnSmall" @onchange="e => OnFilterClick(e.Value.ToString())">
|
||||
@foreach (var filter in Filters)
|
||||
{
|
||||
<option value="@filter">@filter</option>
|
||||
@ -37,7 +37,7 @@
|
||||
@onchange="e => SelectedFile.DraftName = e.Value.ToString()">
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-small is-rounded neoBtn" @onclick="OnFileCloseClick">
|
||||
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileCloseClick">
|
||||
<span class="icon is-medium">
|
||||
<i class="mdi mdi-close"></i>
|
||||
</span>
|
||||
@ -75,13 +75,13 @@
|
||||
|
||||
<div class="filesActions">
|
||||
<div class="buttons is-centered">
|
||||
<button class="button is-rounded neoBtn is-small noBottomMargin" @onclick="OnAddDialog">
|
||||
<button class="button is-rounded neoBtnSmall is-small noBottomMargin" @onclick="OnAddDialog">
|
||||
<span class="icon is-small has-text-success">
|
||||
<i class="mdi mdi-plus-box-outline"></i>
|
||||
</span>
|
||||
<span>Add</span>
|
||||
</button>
|
||||
<button class="button is-rounded neoBtn is-small noBottomMargin @IsSelectedFileDeletable" @onclick="OnDeleteDialog">
|
||||
<button class="button is-rounded neoBtnSmall is-small noBottomMargin @IsSelectedFileDeletable" @onclick="OnDeleteDialog">
|
||||
<span class="icon is-small has-text-danger">
|
||||
<i class="mdi mdi-minus-box-outline"></i>
|
||||
</span>
|
||||
@ -94,10 +94,10 @@
|
||||
@if (IsAnyFileSelected)
|
||||
{
|
||||
<div class="buttons is-centered">
|
||||
<button @onclick="OnSaveDraft" class="button is-rounded neoBtn is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-light"><i class="mdi mdi-content-save-outline"></i></span> <span>Save draft</span></button>
|
||||
<button @onclick="OnUndoChanges" class="button is-rounded neoBtn 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>
|
||||
<button @onclick="OnSave" class="button is-rounded neoBtn 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="OnTest" class="button is-rounded neoBtn 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="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>Save draft</span></button>
|
||||
<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>
|
||||
<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="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>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
|
@ -29,7 +29,7 @@ namespace Seenginx.Components
|
||||
[Parameter]
|
||||
public EventCallback<CFile> UpdateFile { get; set; }
|
||||
[Parameter]
|
||||
public EventCallback<CFile> DeleteFile { get; set; }
|
||||
public EventCallback DeleteFile { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment<CFile> Editor { get; set; } = null;
|
||||
@ -134,7 +134,7 @@ namespace Seenginx.Components
|
||||
{
|
||||
Files.ForEach(f => f.Deselect());
|
||||
file.Select();
|
||||
await JsRuntime.InvokeVoidAsync("UpdateEditor", file.OriginalBody);
|
||||
await JsRuntime.InvokeVoidAsync("UpdateEditor", file.Body);
|
||||
await SelectedFileChanged.InvokeAsync(file);
|
||||
}
|
||||
|
||||
@ -152,13 +152,13 @@ namespace Seenginx.Components
|
||||
}
|
||||
protected async Task OnUndoChanges(MouseEventArgs e)
|
||||
{
|
||||
SelectedFile.DraftBody = SelectedFile.OriginalBody;
|
||||
await JsRuntime.InvokeVoidAsync("UpdateEditor", SelectedFile.OriginalBody);
|
||||
SelectedFile.DraftBody = SelectedFile.Body;
|
||||
await JsRuntime.InvokeVoidAsync("UpdateEditor", SelectedFile.Body);
|
||||
}
|
||||
protected async Task OnSave(MouseEventArgs e)
|
||||
{
|
||||
var draftCode = await JsRuntime.InvokeAsync<string>("GetEditorCode");
|
||||
SelectedFile.OriginalBody = draftCode;
|
||||
SelectedFile.Body = draftCode;
|
||||
}
|
||||
protected async Task OnTest(MouseEventArgs e)
|
||||
{
|
||||
@ -170,7 +170,7 @@ namespace Seenginx.Components
|
||||
}
|
||||
protected async Task OnDeleteDialog()
|
||||
{
|
||||
await UpdateFile.InvokeAsync(SelectedFile);
|
||||
await DeleteFile.InvokeAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
@inherits NginxBase
|
||||
@page "/nginx"
|
||||
|
||||
<p>ciao</p>
|
||||
|
||||
<FilesWithEditor CFile="ConfigFile" Filters="Filters" Files="ConfigFiles" FilterFolder="FilterFolder"
|
||||
SelectedFile="SelectedFile" SelectedFileChanged="SelectedFileChanged"
|
||||
AddFile="AddFile" UpdateFile="UpdateFile" DeleteFile="DeleteFile">
|
||||
AddFile="AddFile" DeleteFile="DeleteFile">
|
||||
</FilesWithEditor>
|
||||
<Modal @ref="ModalRef">
|
||||
<ModalBackdrop />
|
||||
|
@ -14,6 +14,8 @@ namespace Seenginx.Pages
|
||||
{
|
||||
[Inject]
|
||||
public INginxService NginxService { get; set; }
|
||||
[Inject]
|
||||
public IFileManager FileService { get; set; }
|
||||
|
||||
public string InputSearch { get; set; }
|
||||
|
||||
@ -57,11 +59,17 @@ namespace Seenginx.Pages
|
||||
{
|
||||
ShowModal();
|
||||
}
|
||||
public async Task UpdateFile(ConfigFile configFile)
|
||||
{
|
||||
}
|
||||
public async Task DeleteFile(ConfigFile configFile)
|
||||
|
||||
public async Task<Result<ConfigFile>> SaveDraftFileAsync() =>
|
||||
await FileService.SaveUpdateDraftFileAsync(SelectedFile);
|
||||
|
||||
public async Task<Result<ConfigFile>> SaveFileAsync() =>
|
||||
await FileService.SaveUpdateFileAsync(SelectedFile);
|
||||
|
||||
public Result<bool> DeleteFile(EventArgs eventArgs)
|
||||
{
|
||||
return FileService.DeleteFile(SelectedFile);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,26 @@
|
||||
border: none !important;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
&Small {
|
||||
box-shadow: -2px -2px 4px rgba($light-shadow, .5), 2px 2px 4px rgba($dark-shadow, .5);
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
transition: all .2s linear;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
|
||||
&:focus {
|
||||
box-shadow: -2px -2px 4px rgba($light-shadow, .5), 2px 2px 4px rgba($dark-shadow, .5) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: -4px -4px 8px rgba($light-shadow, .5), 4px 4px 8px rgba($dark-shadow, .5);
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&File {
|
||||
|
83
Seenginx/Services/FileManager.cs
Normal file
83
Seenginx/Services/FileManager.cs
Normal file
@ -0,0 +1,83 @@
|
||||
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>> SaveUpdateFileAsync(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(SaveUpdateFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<ConfigFile>> SaveUpdateDraftFileAsync(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(SaveUpdateDraftFileAsync)}(), 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
15
Seenginx/Services/IFileManager.cs
Normal file
15
Seenginx/Services/IFileManager.cs
Normal file
@ -0,0 +1,15 @@
|
||||
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>> SaveUpdateFileAsync(ConfigFile configFile);
|
||||
Task<Result<ConfigFile>> SaveUpdateDraftFileAsync(ConfigFile configFile);
|
||||
Result<bool> DeleteFile(ConfigFile configFile);
|
||||
}
|
||||
}
|
@ -33,7 +33,8 @@ namespace Seenginx.Services
|
||||
configFile.Folder = "/";
|
||||
configFile.LastUpdated = File.GetLastWriteTime(fp);
|
||||
configFile.Name = fileName;
|
||||
configFile.OriginalBody = File.ReadAllText(fp);
|
||||
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
|
||||
configFile.Body = File.ReadAllText(fp);
|
||||
return configFile;
|
||||
});
|
||||
var confdConfigFiles = confdConfigs.Select(fp =>
|
||||
@ -44,7 +45,8 @@ namespace Seenginx.Services
|
||||
configFile.Folder = "/conf.d";
|
||||
configFile.LastUpdated = File.GetLastWriteTime(fp);
|
||||
configFile.Name = fileName;
|
||||
configFile.OriginalBody = File.ReadAllText(fp);
|
||||
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
|
||||
configFile.Body = File.ReadAllText(fp);
|
||||
return configFile;
|
||||
});
|
||||
var sitesAvailableConfigFiles = sitesAvailableConfigs.Select(fp =>
|
||||
@ -55,7 +57,8 @@ namespace Seenginx.Services
|
||||
configFile.Folder = "/sites-available";
|
||||
configFile.LastUpdated = File.GetLastWriteTime(fp);
|
||||
configFile.Name = fileName;
|
||||
configFile.OriginalBody = File.ReadAllText(fp);
|
||||
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
|
||||
configFile.Body = File.ReadAllText(fp);
|
||||
return configFile;
|
||||
});
|
||||
var sitesEnabledConfigFiles = sitesEnabledConfigs.Select(fp =>
|
||||
@ -66,7 +69,8 @@ namespace Seenginx.Services
|
||||
configFile.Folder = "/sites-enabled";
|
||||
configFile.LastUpdated = File.GetLastWriteTime(fp);
|
||||
configFile.Name = fileName;
|
||||
configFile.OriginalBody = File.ReadAllText(fp);
|
||||
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
|
||||
configFile.Body = File.ReadAllText(fp);
|
||||
return configFile;
|
||||
});
|
||||
var finalList = new List<ConfigFile>();
|
||||
|
@ -48,6 +48,7 @@ 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.
|
||||
|
@ -90,6 +90,20 @@ html {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
transform: scale(1.1); }
|
||||
.neoBtnSmall {
|
||||
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;
|
||||
transition: all .2s linear;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden; }
|
||||
.neoBtnSmall:focus {
|
||||
box-shadow: -2px -2px 4px rgba(251, 238, 208, 0.5), 2px 2px 4px rgba(241, 185, 65, 0.5) !important; }
|
||||
.neoBtnSmall:hover {
|
||||
box-shadow: -4px -4px 8px rgba(251, 238, 208, 0.5), 4px 4px 8px rgba(241, 185, 65, 0.5);
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
transform: scale(1.1); }
|
||||
|
||||
.neoFile {
|
||||
box-shadow: 0px 0px 0px rgba(251, 238, 208, 0.5), 0px 0px 0px rgba(241, 185, 65, 0.5) !important;
|
||||
|
2
Seenginx/wwwroot/css/main.min.css
vendored
2
Seenginx/wwwroot/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user