add raw file editing to configuration page in webfront
This commit is contained in:
parent
68c1151191
commit
33c63f01db
@ -135,6 +135,7 @@ namespace SharedLibraryCore.Configuration
|
|||||||
TimeSpan.FromDays(30)
|
TimeSpan.FromDays(30)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[ConfigurationIgnore]
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_PRESET_BAN_REASONS")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_PRESET_BAN_REASONS")]
|
||||||
public Dictionary<string, string> PresetPenaltyReasons { get; set; } = new Dictionary<string, string>
|
public Dictionary<string, string> PresetPenaltyReasons { get; set; } = new Dictionary<string, string>
|
||||||
{{"afk", "Away from keyboard"}, {"ci", "Connection interrupted. Reconnect"}};
|
{{"afk", "Away from keyboard"}, {"ci", "Connection interrupted. Reconnect"}};
|
||||||
@ -150,6 +151,7 @@ namespace SharedLibraryCore.Configuration
|
|||||||
[ConfigurationIgnore]
|
[ConfigurationIgnore]
|
||||||
public TimeSpan ServerDataCollectionInterval { get; set; } = TimeSpan.FromMinutes(5);
|
public TimeSpan ServerDataCollectionInterval { get; set; } = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
[ConfigurationIgnore]
|
||||||
public Dictionary<Permission, string> OverridePermissionLevelNames { get; set; } = Enum
|
public Dictionary<Permission, string> OverridePermissionLevelNames { get; set; } = Enum
|
||||||
.GetValues(typeof(Permission))
|
.GetValues(typeof(Permission))
|
||||||
.Cast<Permission>()
|
.Cast<Permission>()
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
@ -7,7 +9,11 @@ using SharedLibraryCore.Configuration.Validation;
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using WebfrontCore.ViewModels;
|
using WebfrontCore.ViewModels;
|
||||||
|
|
||||||
namespace WebfrontCore.Controllers
|
namespace WebfrontCore.Controllers
|
||||||
@ -36,6 +42,84 @@ namespace WebfrontCore.Controllers
|
|||||||
return View("Index", Manager.GetApplicationSettings().Configuration());
|
return View("Index", Manager.GetApplicationSettings().Configuration());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Files()
|
||||||
|
{
|
||||||
|
if (Client.Level < SharedLibraryCore.Database.Models.EFClient.Permission.Owner)
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// todo: move this into a service a some point
|
||||||
|
var model = await Task.WhenAll(System.IO.Directory
|
||||||
|
.GetFiles(System.IO.Path.Join(Utilities.OperatingDirectory, "Configuration"))
|
||||||
|
.Where(file => file.EndsWith(".json", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
.Select(async fileName => new ConfigurationFileInfo
|
||||||
|
{
|
||||||
|
FileName = fileName.Split(System.IO.Path.DirectorySeparatorChar).Last(),
|
||||||
|
FileContent = await System.IO.File.ReadAllTextAsync(fileName)
|
||||||
|
}));
|
||||||
|
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPatch("{Controller}/File/{fileName}")]
|
||||||
|
public async Task<IActionResult> PatchFiles([FromRoute] string fileName)
|
||||||
|
{
|
||||||
|
if (Client.Level < SharedLibraryCore.Database.Models.EFClient.Permission.Owner)
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileName.EndsWith(".json"))
|
||||||
|
{
|
||||||
|
return BadRequest("File must be of json format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using var reader = new StreamReader(Request.Body, Encoding.UTF8);
|
||||||
|
var content = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(content))
|
||||||
|
{
|
||||||
|
return BadRequest("File content cannot be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var file = JObject.Parse(content);
|
||||||
|
}
|
||||||
|
catch (JsonReaderException ex)
|
||||||
|
{
|
||||||
|
return BadRequest($"{fileName}: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = System.IO.Path.Join(Utilities.OperatingDirectory, "Configuration",
|
||||||
|
fileName.Replace($"{System.IO.Path.DirectorySeparatorChar}", ""));
|
||||||
|
|
||||||
|
// todo: move into a service at some point
|
||||||
|
if (!System.IO.File.Exists(path))
|
||||||
|
{
|
||||||
|
return BadRequest($"{fileName} does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await System.IO.File.WriteAllTextAsync(path, content);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Endpoint for the save action
|
/// Endpoint for the save action
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -58,12 +142,19 @@ namespace WebfrontCore.Controllers
|
|||||||
var currentConfiguration = Manager.GetApplicationSettings().Configuration();
|
var currentConfiguration = Manager.GetApplicationSettings().Configuration();
|
||||||
CopyConfiguration(newConfiguration, currentConfiguration);
|
CopyConfiguration(newConfiguration, currentConfiguration);
|
||||||
await Manager.GetApplicationSettings().Save();
|
await Manager.GetApplicationSettings().Save();
|
||||||
return Ok(new { message = new[] { Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVED"] } });
|
return Ok(new
|
||||||
|
{
|
||||||
|
message = new[] {Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVED"]}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return BadRequest(new { message = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVE_FAILED"], errors = new[] { validationResult.Errors.Select(_error => _error.ErrorMessage) } });
|
return BadRequest(new
|
||||||
|
{
|
||||||
|
message = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVE_FAILED"],
|
||||||
|
errors = new[] {validationResult.Errors.Select(_error => _error.ErrorMessage)}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +167,7 @@ namespace WebfrontCore.Controllers
|
|||||||
void cleanProperties(object config)
|
void cleanProperties(object config)
|
||||||
{
|
{
|
||||||
foreach (var property in config.GetType()
|
foreach (var property in config.GetType()
|
||||||
.GetProperties().Where(_prop => _prop.CanWrite))
|
.GetProperties().Where(_prop => _prop.CanWrite))
|
||||||
{
|
{
|
||||||
var newPropValue = property.GetValue(config);
|
var newPropValue = property.GetValue(config);
|
||||||
|
|
||||||
@ -106,7 +197,8 @@ namespace WebfrontCore.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newConfiguration">Source config</param>
|
/// <param name="newConfiguration">Source config</param>
|
||||||
/// <param name="oldConfiguration">Destination config</param>
|
/// <param name="oldConfiguration">Destination config</param>
|
||||||
private void CopyConfiguration(ApplicationConfiguration newConfiguration, ApplicationConfiguration oldConfiguration)
|
private void CopyConfiguration(ApplicationConfiguration newConfiguration,
|
||||||
|
ApplicationConfiguration oldConfiguration)
|
||||||
{
|
{
|
||||||
foreach (var property in newConfiguration.GetType()
|
foreach (var property in newConfiguration.GetType()
|
||||||
.GetProperties().Where(_prop => _prop.CanWrite))
|
.GetProperties().Where(_prop => _prop.CanWrite))
|
||||||
@ -161,7 +253,7 @@ namespace WebfrontCore.Controllers
|
|||||||
/// <param name="info">property info of the current property</param>
|
/// <param name="info">property info of the current property</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool ShouldIgnoreProperty(PropertyInfo info) => (info.GetCustomAttributes(false)
|
private bool ShouldIgnoreProperty(PropertyInfo info) => (info.GetCustomAttributes(false)
|
||||||
.Where(_attr => _attr.GetType() == typeof(ConfigurationIgnore))
|
.Where(_attr => _attr.GetType() == typeof(ConfigurationIgnore))
|
||||||
.FirstOrDefault() as ConfigurationIgnore) != null;
|
.FirstOrDefault() as ConfigurationIgnore) != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
8
WebfrontCore/ViewModels/ConfigurationFileInfo.cs
Normal file
8
WebfrontCore/ViewModels/ConfigurationFileInfo.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace WebfrontCore.ViewModels
|
||||||
|
{
|
||||||
|
public class ConfigurationFileInfo
|
||||||
|
{
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string FileContent { get; set; }
|
||||||
|
}
|
||||||
|
}
|
58
WebfrontCore/Views/Configuration/Files.cshtml
Normal file
58
WebfrontCore/Views/Configuration/Files.cshtml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
@model IEnumerable<WebfrontCore.ViewModels.ConfigurationFileInfo>
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_TITLE"];
|
||||||
|
var noticeText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CONFIGURATION_SAVING_CHANGES"];
|
||||||
|
static string FormatHtmlId(string value) => value?.Replace(".", "").Replace(" ", "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
@section styles
|
||||||
|
{
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/styles/atom-one-dark.min.css">
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 text-white-50 ">
|
||||||
|
<h3 class="text-white">@ViewData["Title"]</h3>
|
||||||
|
<h5 class="mb-4">@noticeText</h5>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs border-bottom-dark">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" asp-action="Edit">@ViewBag.Localization["WEBFRONT_CONFIGURATION_GUI"]</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" data-toggle="tab" href="#files">@ViewBag.Localization["WEBFRONT_CONFIGURATION_FILES"]</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane" id="editor">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane active" id="files">
|
||||||
|
@foreach (var file in Model)
|
||||||
|
{
|
||||||
|
<div class="bg-primary mb-0 pl-3 pr-3 p-2 text-white d-flex border-bottom-dark">
|
||||||
|
<span class="oi oi-expand-down align-self-center mr-2 expand-file-icon" data-editor-id="#edit_file_@FormatHtmlId(file.FileName)" title="Toggle Expand"></span>
|
||||||
|
<span>@file.FileName</span>
|
||||||
|
</div>
|
||||||
|
<div class="edit-file bg-dark d-none" id="edit_file_@FormatHtmlId(file.FileName)" data-file-name="@file.FileName">
|
||||||
|
<pre class="mb-0 mr-auto" spellcheck="false"><code class="language-json bg-dark editable" contenteditable="true" id="edit_file_code_@FormatHtmlId(file.FileName)">@file.FileContent</code></pre>
|
||||||
|
<button type="button" class="btn btn-primary align-self-end m-3 file-save-button" data-file-name="@file.FileName">Save</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section scripts
|
||||||
|
{
|
||||||
|
<!-- I don't want to include the entire highlight js into the bundle for this 1 page -->
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
|
||||||
|
|
||||||
|
<environment include="Development">
|
||||||
|
<script type="text/javascript" src="~/js/configuration.js"></script>
|
||||||
|
</environment>
|
||||||
|
}
|
||||||
|
</div>
|
@ -16,19 +16,19 @@
|
|||||||
string[] getLinkedPropertyName(System.Reflection.PropertyInfo info)
|
string[] getLinkedPropertyName(System.Reflection.PropertyInfo info)
|
||||||
{
|
{
|
||||||
var test = (info.GetCustomAttributes(false)
|
var test = (info.GetCustomAttributes(false)
|
||||||
.Where(_attr => _attr.GetType() == typeof(ConfigurationLinked))
|
.Where(_attr => _attr.GetType() == typeof(ConfigurationLinked))
|
||||||
.FirstOrDefault() as ConfigurationLinked);
|
.FirstOrDefault() as ConfigurationLinked);
|
||||||
|
|
||||||
return test?.LinkedPropertyNames ?? new string[0];
|
return test?.LinkedPropertyNames ?? new string[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldIgnore(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false)
|
bool shouldIgnore(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false)
|
||||||
.Where(_attr => _attr.GetType() == typeof(ConfigurationIgnore))
|
.Where(_attr => _attr.GetType() == typeof(ConfigurationIgnore))
|
||||||
.FirstOrDefault() as ConfigurationIgnore) != null;
|
.FirstOrDefault() as ConfigurationIgnore) != null;
|
||||||
|
|
||||||
bool isOptional(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false)
|
bool isOptional(System.Reflection.PropertyInfo info) => (info.GetCustomAttributes(false)
|
||||||
.Where(_attr => _attr.GetType() == typeof(ConfigurationOptional))
|
.Where(_attr => _attr.GetType() == typeof(ConfigurationOptional))
|
||||||
.FirstOrDefault() as ConfigurationOptional) != null;
|
.FirstOrDefault() as ConfigurationOptional) != null;
|
||||||
|
|
||||||
bool hasLinkedParent(System.Reflection.PropertyInfo info)
|
bool hasLinkedParent(System.Reflection.PropertyInfo info)
|
||||||
{
|
{
|
||||||
@ -40,88 +40,104 @@
|
|||||||
<div class="col-12 text-white-50 ">
|
<div class="col-12 text-white-50 ">
|
||||||
<h3 class="text-white">@ViewData["Title"]</h3>
|
<h3 class="text-white">@ViewData["Title"]</h3>
|
||||||
<h5 class="mb-4">@noticeText</h5>
|
<h5 class="mb-4">@noticeText</h5>
|
||||||
<form id="configurationForm" asp-controller="Configuration" asp-action="Save" method="post">
|
|
||||||
@foreach (var property in properties)
|
|
||||||
{
|
|
||||||
if (shouldIgnore(property))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] linkedPropertyNames = getLinkedPropertyName(property);
|
<ul class="nav nav-tabs border-bottom-dark">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" data-toggle="tab" href="#editor">GUI Editor</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" asp-action="Files">Files</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
// bool type
|
<div class="tab-content">
|
||||||
if (property.PropertyType == typeof(bool))
|
<div class="tab-pane active" id="editor">
|
||||||
{
|
<form id="configurationForm" asp-controller="Configuration" asp-action="Save" method="post">
|
||||||
<div class="form-group form-check bg-primary mb-0 pl-3 pr-3 p-2">
|
@foreach (var property in properties)
|
||||||
@Html.Editor(property.Name, linkedPropertyNames.Length > 0 ? new { htmlAttributes = new { @class = "has-related-content mb-0", data_related_content = string.Join(',', linkedPropertyNames.Select(_id => $"#{_id}_content")) } } : null)
|
|
||||||
@Html.Label(property.Name, null, new { @class = "form-check-label ml-1" })
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
// array type
|
|
||||||
else if (property.PropertyType.IsArray)
|
|
||||||
{
|
|
||||||
// special type for server config, I don't like this but for now it's ok
|
|
||||||
@if (property.PropertyType.GetElementType() == typeof(ServerConfiguration))
|
|
||||||
{
|
{
|
||||||
<div id="@($"{property.Name}_content")" class="pl-3 pr-3 pt-2 pb-3 bg-dark">
|
if (shouldIgnore(property))
|
||||||
@for (int i = 0; i < Model.Servers.Length; i++)
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] linkedPropertyNames = getLinkedPropertyName(property);
|
||||||
|
|
||||||
|
// bool type
|
||||||
|
if (property.PropertyType == typeof(bool))
|
||||||
|
{
|
||||||
|
<div class="form-group form-check bg-primary mb-0 pl-3 pr-3 p-2">
|
||||||
|
@Html.Editor(property.Name, linkedPropertyNames.Length > 0 ? new {htmlAttributes = new {@class = "has-related-content mb-0", data_related_content = string.Join(',', linkedPropertyNames.Select(_id => $"#{_id}_content"))}} : null)
|
||||||
|
@Html.Label(property.Name, null, new {@class = "form-check-label ml-1"})
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
// array type
|
||||||
|
else if (property.PropertyType.IsArray)
|
||||||
|
{
|
||||||
|
// special type for server config, I don't like this but for now it's ok
|
||||||
|
@if (property.PropertyType.GetElementType() == typeof(ServerConfiguration))
|
||||||
{
|
{
|
||||||
@Html.EditorFor(model => model.Servers[i]);
|
<div id="@($"{property.Name}_content")" class="pl-3 pr-3 pt-2 pb-3 bg-dark">
|
||||||
|
@for (int i = 0; i < Model.Servers.Length; i++)
|
||||||
|
{
|
||||||
|
@Html.EditorFor(model => model.Servers[i])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
<a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-server-add-new">@addServerText</a>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
<a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-server-add-new">@addServerText</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (hasLinkedParent(property))
|
else if (hasLinkedParent(property))
|
||||||
{
|
|
||||||
<div id="@($"{property.Name}_content")" class="@(linkedPropertyNames.Length == 0 ? "hide" : "hide") bg-dark pl-3 pr-3 pb-2">
|
|
||||||
@if (linkedPropertyNames.Length == 0)
|
|
||||||
{
|
{
|
||||||
@Html.Label(property.Name, null, new { @class = "mt-2 d-block" })
|
<div id="@($"{property.Name}_content")" class="@(linkedPropertyNames.Length == 0 ? "hide" : "hide") bg-dark pl-3 pr-3 pb-2">
|
||||||
|
@if (linkedPropertyNames.Length == 0)
|
||||||
|
{
|
||||||
|
@Html.Label(property.Name, null, new {@class = "mt-2 d-block"})
|
||||||
|
}
|
||||||
|
@Html.Editor(property.Name, new {htmlAttributes = new {@class = $"form-group form-control bg-dark text-white-50 {(linkedPropertyNames.Length == 0 ? "mb-3" : "mb-0")}"}})
|
||||||
|
<a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-add-new">@addText</a>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
@Html.Editor(property.Name, new { htmlAttributes = new { @class = $"form-group form-control bg-dark text-white-50 {(linkedPropertyNames.Length == 0 ? "mb-3" : "mb-0")}" } })
|
|
||||||
<a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-add-new">@addText</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@Html.Label(property.Name, null, new { @class = "bg-primary pl-3 pr-3 p-2 mb-0 w-100" })
|
@Html.Label(property.Name, null, new {@class = "bg-primary pl-3 pr-3 p-2 mb-0 w-100"})
|
||||||
<div id="@($"{property.Name}_content")" class="pl-3 pr-3 pt-2 pb-3 bg-dark">
|
<div id="@($"{property.Name}_content")" class="pl-3 pr-3 pt-2 pb-3 bg-dark">
|
||||||
@Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-control bg-dark text-white-50 mt-3 mb-3", placeholder = isOptional(property) ? optionalText : "" } })
|
@Html.Editor(property.Name, new {htmlAttributes = new {@class = "form-control bg-dark text-white-50 mt-3 mb-3", placeholder = isOptional(property) ? optionalText : ""}})
|
||||||
<a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-add-new">@addText</a>
|
<a asp-controller="Configuration" asp-action="GetNewListItem" asp-route-propertyName="@property.Name" class="btn btn-primary configuration-add-new">@addText</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hasLinkedParent(property))
|
if (hasLinkedParent(property))
|
||||||
{
|
{
|
||||||
<div id="@($"{property.Name}_content")" class="@(hasLinkedParent(property) ? "hide" : "") bg-dark pl-3 pr-3 pt-2 pb-3">
|
<div id="@($"{property.Name}_content")" class="@(hasLinkedParent(property) ? "hide" : "") bg-dark pl-3 pr-3 pt-2 pb-3">
|
||||||
@Html.Label(property.Name, null, new { @class = "mt-1" })
|
@Html.Label(property.Name, null, new {@class = "mt-1"})
|
||||||
@Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : "" } })
|
@Html.Editor(property.Name, new {htmlAttributes = new {@class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : ""}})
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@Html.Label(property.Name, null, new { @class = "bg-primary pl-3 pr-3 p-2 mb-0 w-100" })
|
@Html.Label(property.Name, null, new {@class = "bg-primary pl-3 pr-3 p-2 mb-0 w-100"})
|
||||||
<div class="p-3 bg-dark">
|
<div class="p-3 bg-dark">
|
||||||
@Html.Editor(property.Name, new { htmlAttributes = new { @class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : "" } })
|
@Html.Editor(property.Name, new {htmlAttributes = new {@class = "form-group form-control bg-dark text-white-50 mb-0", placeholder = isOptional(property) ? optionalText : ""}})
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
<button class="btn btn-primary btn-block">@saveText</button>
|
||||||
}
|
</form>
|
||||||
<button class="btn btn-primary btn-block">@saveText</button>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section scripts {
|
@section scripts {
|
||||||
<environment include="Development">
|
<environment include="Development">
|
||||||
<script type="text/javascript" src="~/js/configuration.js"></script>
|
<script type="text/javascript" src="~/js/configuration.js"></script>
|
||||||
</environment>
|
</environment>
|
||||||
}
|
}
|
||||||
|
|
@ -23,6 +23,7 @@
|
|||||||
<environment include="Production">
|
<environment include="Production">
|
||||||
<link rel="stylesheet" href="~/dynamic/css/global.min.css?version=@ViewBag.Version" />
|
<link rel="stylesheet" href="~/dynamic/css/global.min.css?version=@ViewBag.Version" />
|
||||||
</environment>
|
</environment>
|
||||||
|
@await RenderSectionAsync("styles", false)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
@ -37,6 +37,10 @@ a.nav-link {
|
|||||||
border-bottom: 1px solid $primary !important;
|
border-bottom: 1px solid $primary !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-bottom-dark {
|
||||||
|
border-bottom: 1px solid $body-bg !important;
|
||||||
|
}
|
||||||
|
|
||||||
.server-history {
|
.server-history {
|
||||||
background-color: $big-dark;
|
background-color: $big-dark;
|
||||||
}
|
}
|
||||||
|
@ -73,4 +73,49 @@
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
hljs.highlightAll();
|
||||||
|
$('.edit-file' ).on('keydown .editable', function(e){
|
||||||
|
if(e.keyCode === 9) {
|
||||||
|
document.execCommand ( 'styleWithCSS', true, null )
|
||||||
|
document.execCommand ( 'insertText', true, ' ' )
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.expand-file-icon').click((e) => {
|
||||||
|
const selector = $(e.target).data('editor-id');
|
||||||
|
$(selector).toggleClass('d-none').toggleClass('d-flex');
|
||||||
|
$(e.target).toggleClass('oi-expand-up', 'oi-expand-down');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.file-save-button').click(e => {
|
||||||
|
const id = $(e.target).prev().find('.editable').attr('id');
|
||||||
|
const content = document.getElementById(id).textContent;
|
||||||
|
const file = $(e.target).data('file-name');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
data: content,
|
||||||
|
type: 'PATCH',
|
||||||
|
url: 'File/' + file,
|
||||||
|
contentType: 'text/plain',
|
||||||
|
complete: function(response) {
|
||||||
|
if (response.status !== 204) {
|
||||||
|
$('#actionModal').modal();
|
||||||
|
$('#actionModal .modal-message').text(response.responseText);
|
||||||
|
$('#actionModal .modal-message').addClass('text-danger');
|
||||||
|
$('#actionModal .modal-message').fadeIn('fast');
|
||||||
|
$(e.target).toggleClass('btn-danger');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(e.target).removeClass('btn-danger')
|
||||||
|
$(e.target).toggleClass('btn-success')
|
||||||
|
window.setTimeout(function() {
|
||||||
|
$(e.target).toggleClass('btn-success');
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user