mirror of
https://github.com/Theodor-Springmann-Stiftung/hamann-ausgabe-core.git
synced 2025-10-29 09:15:33 +00:00
Deployment v1
This commit is contained in:
@@ -19,88 +19,50 @@ using System.Runtime.InteropServices;
|
|||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
public class FileListForm {
|
||||||
|
public string file { get; set; }
|
||||||
|
public string __RequestVerificationToken { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
// Controlling all the API-Endpoints
|
// Controlling all the API-Endpoints
|
||||||
[FeatureGate(Features.AdminService)]
|
[FeatureGate(Features.AdminService)]
|
||||||
|
[ApiController]
|
||||||
public class APIController : Controller {
|
public class APIController : Controller {
|
||||||
|
|
||||||
// DI
|
// DI
|
||||||
private IHaDocumentWrappper _lib;
|
private readonly IHaDocumentWrappper _lib;
|
||||||
private readonly IXMLFileProvider _xmlProvider;
|
private readonly IXMLFileProvider _xmlProvider;
|
||||||
|
private readonly IXMLInteractionService _xmlService;
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
private static readonly FormOptions _defaultFormOptions = new FormOptions();
|
private static readonly FormOptions _defaultFormOptions = new FormOptions();
|
||||||
|
|
||||||
|
|
||||||
public APIController(IHaDocumentWrappper lib, IXMLFileProvider xmlProvider) {
|
public APIController(IHaDocumentWrappper lib, IXMLInteractionService xmlService, IXMLFileProvider xmlProvider) {
|
||||||
_lib = lib;
|
_lib = lib;
|
||||||
_xmlProvider = xmlProvider;
|
_xmlProvider = xmlProvider;
|
||||||
|
_xmlService = xmlService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: this is trash
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("API/SetInProduction")]
|
[Route("API/SetInProduction")]
|
||||||
[DisableFormValueModelBinding]
|
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
[FeatureGate(Features.LocalPublishService, Features.AdminService)]
|
[FeatureGate(Features.LocalPublishService, Features.AdminService)]
|
||||||
public async Task<IActionResult> SetInProduction() {
|
public async Task<IActionResult> SetInProduction([FromForm] FileListForm _form) {
|
||||||
var hF = _xmlProvider.GetHamannFiles();
|
var hF = _xmlProvider.GetHamannFiles();
|
||||||
if (hF == null) {
|
if (hF == null) {
|
||||||
ModelState.AddModelError("Error", "There are no Hamman.xml files available.");
|
ModelState.AddModelError("Error", "There are no Hamman.xml files available.");
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) {
|
if (_form == null || String.IsNullOrWhiteSpace(_form.file)) {
|
||||||
ModelState.AddModelError("Error", $"Wrong / No Content Type on the Request");
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same as above, check Upload()
|
|
||||||
string? filename = null;
|
|
||||||
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
|
|
||||||
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
|
|
||||||
MultipartSection? section = null;
|
|
||||||
try {
|
|
||||||
section = await reader.ReadNextSectionAsync();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (section != null) {
|
|
||||||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
|
|
||||||
|
|
||||||
if (contentDisposition != null && contentDisposition.Name == "__RequestVerificationToken") {
|
|
||||||
try {
|
|
||||||
section = await reader.ReadNextSectionAsync();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasContentDispositionHeader && contentDisposition != null) {
|
|
||||||
if (!MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) {
|
|
||||||
ModelState.AddModelError("Error", $"Wrong Content-Dispostion Headers in Multipart Document");
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = XMLFileHelpers.StreamToString(section.Body, ModelState);
|
|
||||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
section = await reader.ReadNextSectionAsync();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filename == null) {
|
|
||||||
ModelState.AddModelError("Error", "Kein Dateiname.");
|
ModelState.AddModelError("Error", "Kein Dateiname.");
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
var newFile = hF.Where(x => x.Name == filename);
|
var newFile = hF.Where(x => x.Name == _form.file);
|
||||||
if (newFile == null || !newFile.Any()) {
|
if (newFile == null || !newFile.Any()) {
|
||||||
ModelState.AddModelError("Error", "Versuch, auf eine unverfügbare Datei zuzugreifen.");
|
ModelState.AddModelError("Error", "Versuch, auf eine unverfügbare Datei zuzugreifen.");
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
@@ -110,4 +72,19 @@ public class APIController : Controller {
|
|||||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||||
return Created("/", newFile.First());
|
return Created("/", newFile.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("API/SyntaxCheck")]
|
||||||
|
// [ValidateAntiForgeryToken]
|
||||||
|
[DisableFormValueModelBinding]
|
||||||
|
[FeatureGate(Features.SyntaxCheck, Features.AdminService)]
|
||||||
|
public ActionResult<Dictionary<string, SyntaxCheckModel>?> GetSyntaxCheck(string? id) {
|
||||||
|
var SCCache = _xmlService.GetSCCache();
|
||||||
|
if (_xmlProvider.HasChanged() || SCCache == null) {
|
||||||
|
var commit = _xmlProvider.GetGitState();
|
||||||
|
SCCache = _xmlService.Test(_xmlService.GetState(), commit != null ? commit.Commit : string.Empty);
|
||||||
|
_xmlService.SetSCCache(SCCache);
|
||||||
|
}
|
||||||
|
return Ok(SCCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -185,11 +185,11 @@ public class Briefecontroller : Controller {
|
|||||||
foreach (var str in strlist) {
|
foreach (var str in strlist) {
|
||||||
if (str != strlist.First())
|
if (str != strlist.First())
|
||||||
if (str == strlist.Last())
|
if (str == strlist.Last())
|
||||||
res += " und " + HTMLHelpers.TagHelpers.CreateElement("a", "", "/HKB/Person/" + str.Index) + str.Name + HTMLHelpers.TagHelpers.CreateEndElement("a");
|
res += " und " + (str.Index == "1" ? "" : HTMLHelpers.TagHelpers.CreateElement("a", "", "/HKB/Person/" + str.Index)) + str.Name + (str.Index == "1" ? "" : HTMLHelpers.TagHelpers.CreateEndElement("a"));
|
||||||
else
|
else
|
||||||
res += ", " + HTMLHelpers.TagHelpers.CreateElement("a", "", "/HKB/Person/" + str.Index) + str.Name + HTMLHelpers.TagHelpers.CreateEndElement("a");
|
res += ", " + (str.Index == "1" ? "" :HTMLHelpers.TagHelpers.CreateElement("a", "", "/HKB/Person/" + str.Index)) + str.Name + (str.Index == "1" ? "" : HTMLHelpers.TagHelpers.CreateEndElement("a"));
|
||||||
else
|
else
|
||||||
res += HTMLHelpers.TagHelpers.CreateElement("a", "", "/HKB/Person/" + str.Index) + str.Name + HTMLHelpers.TagHelpers.CreateEndElement("a");
|
res += (str.Index == "1" ? "" : HTMLHelpers.TagHelpers.CreateElement("a", "", "/HKB/Person/" + str.Index)) + str.Name + (str.Index == "1" ? "" : HTMLHelpers.TagHelpers.CreateEndElement("a"));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,18 +25,15 @@ public class XMLStateController : Controller {
|
|||||||
[GenerateAntiforgeryTokenCookie]
|
[GenerateAntiforgeryTokenCookie]
|
||||||
public IActionResult Index() {
|
public IActionResult Index() {
|
||||||
var library = _lib.GetLibrary();
|
var library = _lib.GetLibrary();
|
||||||
var roots = _xmlService.GetRootsList();
|
|
||||||
if (roots == null) return error404();
|
|
||||||
|
|
||||||
var hF = _xmlProvider.GetHamannFiles()?.OrderByDescending(x => x.LastModified).ToList();
|
var hF = _xmlProvider.GetHamannFiles()?.OrderByDescending(x => x.LastModified).ToList();
|
||||||
var mF = _xmlService.GetManagedFiles();
|
var mF = _xmlService.GetState() == null ? null : _xmlService.GetState()!.ManagedFiles;
|
||||||
var gD = _xmlProvider.GetGitData();
|
var gD = _xmlProvider.GetGitState();
|
||||||
var activeF = _lib.GetActiveFile();
|
var activeF = _lib.GetActiveFile();
|
||||||
var vS = _xmlService.GetValidState();
|
var vS = _xmlService.GetState() == null ? false : _xmlService.GetState()!.ValidState;
|
||||||
|
|
||||||
var model = new XMLStateViewModel("Dateiübersicht", gD, roots, hF, mF, vS) {
|
var model = new XMLStateViewModel("Dateiübersicht", gD, hF, mF, vS) {
|
||||||
ActiveFile = activeF,
|
ActiveFile = activeF,
|
||||||
SyntaxCheck = _xmlService.Test()
|
SyntaxCheck = _xmlService.GetSCCache(),
|
||||||
};
|
};
|
||||||
return View("~/Views/Admin/Dynamic/XMLState.cshtml", model);
|
return View("~/Views/Admin/Dynamic/XMLState.cshtml", model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ public class ConfigurationMonitor {
|
|||||||
_h = h;
|
_h = h;
|
||||||
_timer = new(8000) { AutoReset = false };
|
_timer = new(8000) { AutoReset = false };
|
||||||
_timer.Enabled = true;
|
_timer.Enabled = true;
|
||||||
_timer.Elapsed += OnChanged;
|
_timer.Elapsed += _OnChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnChanged(Object source, System.Timers.ElapsedEventArgs e) {
|
private void _OnChanged(Object source, System.Timers.ElapsedEventArgs e) {
|
||||||
Console.WriteLine("Configuration changed (ConfigurationMonitor Class)");
|
Console.WriteLine("Configuration changed (ConfigurationMonitor Class)");
|
||||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||||
IServiceProvider provider = serviceScope.ServiceProvider;
|
IServiceProvider provider = serviceScope.ServiceProvider;
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ using HaWeb.Models;
|
|||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
public interface IXMLFileProvider {
|
public interface IXMLFileProvider {
|
||||||
|
public event EventHandler<GitState?> FileChange;
|
||||||
|
public event EventHandler<XMLParsingState?> NewState;
|
||||||
|
public event EventHandler NewData;
|
||||||
|
public event EventHandler ConfigReload;
|
||||||
public List<IFileInfo>? GetWorkingTreeFiles();
|
public List<IFileInfo>? GetWorkingTreeFiles();
|
||||||
public IFileInfo? SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary ModelState);
|
public IFileInfo? SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary ModelState);
|
||||||
public List<IFileInfo>? GetHamannFiles();
|
public List<IFileInfo>? GetHamannFiles();
|
||||||
public (DateTime PullTime, string Hash)? GetGitData();
|
public GitState? GetGitState();
|
||||||
public void ParseConfiguration(IConfiguration config);
|
public void ParseConfiguration(IConfiguration config);
|
||||||
public bool HasChanged();
|
public bool HasChanged();
|
||||||
public void DeleteHamannFile(string filename);
|
public void DeleteHamannFile(string filename);
|
||||||
|
|||||||
@@ -80,26 +80,26 @@ public static class XMLFileHelpers {
|
|||||||
public static bool ProcessFile(
|
public static bool ProcessFile(
|
||||||
Stream file,
|
Stream file,
|
||||||
string fileName,
|
string fileName,
|
||||||
StringBuilder errorMessages,
|
Action<string> logger,
|
||||||
string[] permittedExtensions,
|
string[] permittedExtensions,
|
||||||
long sizeLimit) {
|
long sizeLimit) {
|
||||||
try {
|
try {
|
||||||
// Check if the file is empty or exceeds the size limit.
|
// Check if the file is empty or exceeds the size limit.
|
||||||
if (file.Length == 0) {
|
if (file.Length == 0) {
|
||||||
errorMessages.AppendLine("Die Datei ist leer.");
|
logger("Die Datei ist leer.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (file.Length > sizeLimit) {
|
else if (file.Length > sizeLimit) {
|
||||||
var megabyteSizeLimit = sizeLimit / 1048576;
|
var megabyteSizeLimit = sizeLimit / 1048576;
|
||||||
errorMessages.AppendLine($"Die Datei überschreitet das Größenlimit {megabyteSizeLimit:N1} MB.");
|
logger($"Die Datei überschreitet das Größenlimit {megabyteSizeLimit:N1} MB.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return orderly, if signature & extension okay
|
// Return orderly, if signature & extension okay
|
||||||
else return IsValidFileExtensionAndSignature(fileName, file, errorMessages, permittedExtensions);
|
else return IsValidFileExtensionAndSignature(fileName, file, logger, permittedExtensions);
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
errorMessages.AppendLine($"The upload failed. Error: {ex.Message}");
|
logger($"The upload failed. Error: {ex.Message}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,13 +118,13 @@ public static class XMLFileHelpers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsValidFileExtensionAndSignature(string fileName, Stream data, StringBuilder errorMessages, string[] permittedExtensions) {
|
private static bool IsValidFileExtensionAndSignature(string fileName, Stream data, Action<string> logger, string[] permittedExtensions) {
|
||||||
if (string.IsNullOrEmpty(fileName) || data == null || data.Length == 0)
|
if (string.IsNullOrEmpty(fileName) || data == null || data.Length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
||||||
if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext)) {
|
if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext)) {
|
||||||
errorMessages.AppendLine("Dateiname endet nicht auf .xml");
|
logger("Dateiname endet nicht auf .xml");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ public static class XMLFileHelpers {
|
|||||||
var headerBytes = reader.ReadBytes(signatures.Max(m => m.Length));
|
var headerBytes = reader.ReadBytes(signatures.Max(m => m.Length));
|
||||||
if (!signatures.Any(signature =>
|
if (!signatures.Any(signature =>
|
||||||
headerBytes.Take(signature.Length).SequenceEqual(signature))) {
|
headerBytes.Take(signature.Length).SequenceEqual(signature))) {
|
||||||
errorMessages.AppendLine("Datei muss mit <?xml version=\"1.0\" encoding=\"utf-8\"?> oder <?xml version=\"1.0\"?> beginnen.");
|
logger("Datei muss mit <?xml version=\"1.0\" encoding=\"utf-8\"?> oder <?xml version=\"1.0\"?> beginnen.");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using HaWeb.XMLTests;
|
|||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
// XMLProvider provides a wrapper around the available XML data on a FILE basis
|
// XMLProvider provides a wrapper around the available XML data on a FILE basis
|
||||||
public class XMLFileProvider : IXMLFileProvider {
|
public class XMLFileProvider : IXMLFileProvider {
|
||||||
@@ -16,13 +17,20 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
private IFileProvider _hamannFileProvider;
|
private IFileProvider _hamannFileProvider;
|
||||||
private IFileProvider _bareRepositoryFileProvider;
|
private IFileProvider _bareRepositoryFileProvider;
|
||||||
private IFileProvider _workingTreeFileProvider;
|
private IFileProvider _workingTreeFileProvider;
|
||||||
|
|
||||||
|
public event EventHandler<GitState?> FileChange;
|
||||||
|
public event EventHandler ConfigReload;
|
||||||
|
public event EventHandler<XMLParsingState?> NewState;
|
||||||
|
public event EventHandler NewData;
|
||||||
|
|
||||||
private string _Branch;
|
private string _Branch;
|
||||||
|
private string _URL;
|
||||||
|
|
||||||
private List<IFileInfo>? _WorkingTreeFiles;
|
private List<IFileInfo>? _WorkingTreeFiles;
|
||||||
private List<IFileInfo>? _HamannFiles;
|
private List<IFileInfo>? _HamannFiles;
|
||||||
|
|
||||||
private static (DateTime PullTime, string Hash)? _GitData;
|
private GitState? _GitState;
|
||||||
|
private System.Timers.Timer? _changeTokenTimer;
|
||||||
|
|
||||||
// Startup (LAST)
|
// Startup (LAST)
|
||||||
public XMLFileProvider(IXMLInteractionService xmlservice, IHaDocumentWrappper _lib, IConfiguration config) {
|
public XMLFileProvider(IXMLInteractionService xmlservice, IHaDocumentWrappper _lib, IConfiguration config) {
|
||||||
@@ -31,6 +39,7 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
_XMLService = xmlservice;
|
_XMLService = xmlservice;
|
||||||
|
|
||||||
_Branch = config.GetValue<string>("RepositoryBranch");
|
_Branch = config.GetValue<string>("RepositoryBranch");
|
||||||
|
_URL = config.GetValue<string>("RepositoryURL");
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||||
_hamannFileProvider = new PhysicalFileProvider(config.GetValue<string>("HamannFileStoreWindows"));
|
_hamannFileProvider = new PhysicalFileProvider(config.GetValue<string>("HamannFileStoreWindows"));
|
||||||
_bareRepositoryFileProvider = new PhysicalFileProvider(config.GetValue<string>("BareRepositoryPathWindows"));
|
_bareRepositoryFileProvider = new PhysicalFileProvider(config.GetValue<string>("BareRepositoryPathWindows"));
|
||||||
@@ -45,10 +54,12 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
// Create File Lists; Here and in xmlservice, which does preliminary checking
|
// Create File Lists; Here and in xmlservice, which does preliminary checking
|
||||||
Scan();
|
Scan();
|
||||||
if (_WorkingTreeFiles != null && _WorkingTreeFiles.Any()) {
|
if (_WorkingTreeFiles != null && _WorkingTreeFiles.Any()) {
|
||||||
xmlservice.Collect(_WorkingTreeFiles);
|
var state = xmlservice.Collect(_WorkingTreeFiles, xmlservice.GetRootDefs());
|
||||||
|
xmlservice.SetState(state);
|
||||||
}
|
}
|
||||||
_HamannFiles = _ScanHamannFiles();
|
_HamannFiles = _ScanHamannFiles();
|
||||||
|
|
||||||
|
_RegisterChangeToken();
|
||||||
// Check if hamann file already is current working tree status
|
// Check if hamann file already is current working tree status
|
||||||
// -> YES: Load up the file via _lib.SetLibrary();
|
// -> YES: Load up the file via _lib.SetLibrary();
|
||||||
if (_IsAlreadyParsed()) {
|
if (_IsAlreadyParsed()) {
|
||||||
@@ -57,7 +68,7 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -> NO: Try to create a new file
|
// -> NO: Try to create a new file
|
||||||
var created = _XMLService.TryCreate();
|
var created = _XMLService.TryCreate(_XMLService.GetState());
|
||||||
if (created != null) {
|
if (created != null) {
|
||||||
var file = SaveHamannFile(created, _hamannFileProvider.GetFileInfo("./").PhysicalPath, null);
|
var file = SaveHamannFile(created, _hamannFileProvider.GetFileInfo("./").PhysicalPath, null);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
@@ -87,10 +98,11 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
Scan();
|
Scan();
|
||||||
// Reset XMLInteractionService
|
// Reset XMLInteractionService
|
||||||
if (_WorkingTreeFiles != null && _WorkingTreeFiles.Any()) {
|
if (_WorkingTreeFiles != null && _WorkingTreeFiles.Any()) {
|
||||||
_XMLService.Collect(_WorkingTreeFiles);
|
var state = _XMLService.Collect(_WorkingTreeFiles, _XMLService.GetRootDefs());
|
||||||
|
_XMLService.SetState(state);
|
||||||
}
|
}
|
||||||
_HamannFiles = _ScanHamannFiles();
|
_HamannFiles = _ScanHamannFiles();
|
||||||
|
_XMLService.SetSCCache(null);
|
||||||
if (_HamannFiles != null && _HamannFiles.Select(x => x.Name).Contains(_Lib.GetActiveFile().Name)) {
|
if (_HamannFiles != null && _HamannFiles.Select(x => x.Name).Contains(_Lib.GetActiveFile().Name)) {
|
||||||
_Lib.SetLibrary(_Lib.GetActiveFile(), null, null);
|
_Lib.SetLibrary(_Lib.GetActiveFile(), null, null);
|
||||||
if (_Lib.GetLibrary() != null) return;
|
if (_Lib.GetLibrary() != null) return;
|
||||||
@@ -105,7 +117,7 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -> NO: Try to create a new file
|
// -> NO: Try to create a new file
|
||||||
var created = _XMLService.TryCreate();
|
var created = _XMLService.TryCreate(_XMLService.GetState());
|
||||||
if (created != null) {
|
if (created != null) {
|
||||||
var file = SaveHamannFile(created, _hamannFileProvider.GetFileInfo("./").PhysicalPath, null);
|
var file = SaveHamannFile(created, _hamannFileProvider.GetFileInfo("./").PhysicalPath, null);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
@@ -132,7 +144,7 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
public List<IFileInfo>? GetWorkingTreeFiles() => _WorkingTreeFiles;
|
public List<IFileInfo>? GetWorkingTreeFiles() => _WorkingTreeFiles;
|
||||||
|
|
||||||
public (DateTime PullTime, string Hash)? GetGitData() => _GitData;
|
public GitState? GetGitState() => _GitState;
|
||||||
|
|
||||||
public List<IFileInfo>? GetHamannFiles() => this._HamannFiles;
|
public List<IFileInfo>? GetHamannFiles() => this._HamannFiles;
|
||||||
|
|
||||||
@@ -148,12 +160,12 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
|
|
||||||
public void Scan() {
|
public void Scan() {
|
||||||
_WorkingTreeFiles = _ScanWorkingTreeFiles();
|
_WorkingTreeFiles = _ScanWorkingTreeFiles();
|
||||||
_GitData = _ScanGitData();
|
_GitState = _ScanGitData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileInfo? SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary? ModelState) {
|
public IFileInfo? SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary? ModelState) {
|
||||||
if (!_GitData.HasValue) return null;
|
if (_GitState == null) return null;
|
||||||
var filename = "hamann_" + _GitData.Value.PullTime.Year + "-" + _GitData.Value.PullTime.Month + "-" + _GitData.Value.PullTime.Day + "_" + _GitData.Value.PullTime.Hour + "-" + _GitData.Value.PullTime.Minute + "." + _GitData.Value.Hash.Substring(0,7) + ".xml";
|
var filename = "hamann_" + _GitState.PullTime.Year + "-" + _GitState.PullTime.Month + "-" + _GitState.PullTime.Day + "_" + _GitState.PullTime.Hour + "-" + _GitState.PullTime.Minute + "." + _GitState.Commit.Substring(0,7) + ".xml";
|
||||||
var path = Path.Combine(basefilepath, filename);
|
var path = Path.Combine(basefilepath, filename);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -179,22 +191,29 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool HasChanged() {
|
public bool HasChanged() {
|
||||||
if (!_GitData.HasValue) return true;
|
if (_GitState == null) return true;
|
||||||
var current = _ScanGitData();
|
var current = _ScanGitData();
|
||||||
if (current.Item2 != _GitData.Value.Hash) {
|
if (current != null && !String.Equals(current.Commit, _GitState.Commit)) {
|
||||||
_GitData = current;
|
_GitState = current;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (DateTime, string) _ScanGitData() {
|
private GitState? _ScanGitData() {
|
||||||
var head = _bareRepositoryFileProvider.GetFileInfo("refs/heads/" + _Branch);
|
var head = _bareRepositoryFileProvider.GetFileInfo("refs/heads/" + _Branch);
|
||||||
return (head.LastModified.DateTime, File.ReadAllText(head.PhysicalPath));
|
// TODO: Failsave reading from FIle
|
||||||
}
|
try {
|
||||||
|
return new GitState {
|
||||||
private void _RegisterChangeCallbacks() {
|
URL = _URL,
|
||||||
var cT = _bareRepositoryFileProvider.Watch("refs/heads/" + _Branch);
|
Branch = _Branch,
|
||||||
|
PullTime = head.LastModified.ToLocalTime().DateTime,
|
||||||
|
Commit = File.ReadAllText(head.PhysicalPath).Trim()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets all XML Files
|
// Gets all XML Files
|
||||||
@@ -216,9 +235,70 @@ public class XMLFileProvider : IXMLFileProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool _IsAlreadyParsed() {
|
private bool _IsAlreadyParsed() {
|
||||||
if (_HamannFiles == null || !_HamannFiles.Any() || !_GitData.HasValue) return false;
|
if (_HamannFiles == null || !_HamannFiles.Any() || _GitState == null) return false;
|
||||||
var fhash = _GetHashFromHamannFilename(_HamannFiles.First().Name);
|
var fhash = _GetHashFromHamannFilename(_HamannFiles.First().Name);
|
||||||
var ghash = _GitData.Value.Hash.Substring(0,7);
|
var ghash = _GitState.Commit.Substring(0,7);
|
||||||
return fhash == ghash;
|
return fhash == ghash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void _RegisterChangeToken() {
|
||||||
|
ChangeToken.OnChange(
|
||||||
|
() => _bareRepositoryFileProvider.Watch("refs/heads/" + _Branch),
|
||||||
|
async (state) => await this._InvokeChanged(state),
|
||||||
|
this._ScanGitData()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _InvokeChanged(GitState? gitdata) {
|
||||||
|
if (_changeTokenTimer != null) return;
|
||||||
|
Console.WriteLine("FILECHANGE DETECTED, RELOAD");
|
||||||
|
Scan();
|
||||||
|
|
||||||
|
OnFileChange(_ScanGitData());
|
||||||
|
// Reset XMLInteractionService
|
||||||
|
if (_WorkingTreeFiles != null && _WorkingTreeFiles.Any()) {
|
||||||
|
var state = _XMLService.Collect(_WorkingTreeFiles, _XMLService.GetRootDefs());
|
||||||
|
_XMLService.SetState(state);
|
||||||
|
OnNewState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -> Try to create a new file
|
||||||
|
var created = _XMLService.TryCreate(_XMLService.GetState());
|
||||||
|
if (created != null) {
|
||||||
|
var file = SaveHamannFile(created, _hamannFileProvider.GetFileInfo("./").PhysicalPath, null);
|
||||||
|
if (file != null) {
|
||||||
|
var ret = _Lib.SetLibrary(file, created.Document, null);
|
||||||
|
if (ret != null) OnNewData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_XMLService.SetSCCache(null);
|
||||||
|
_GitState = _ScanGitData();
|
||||||
|
_changeTokenTimer = new(5000) { AutoReset = false, Enabled = true };
|
||||||
|
_changeTokenTimer.Elapsed += this._OnElapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _OnElapsed(Object source, System.Timers.ElapsedEventArgs e) {
|
||||||
|
_changeTokenTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnFileChange(GitState? state) {
|
||||||
|
EventHandler<GitState?> eh = FileChange;
|
||||||
|
eh?.Invoke(this, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnNewState(XMLParsingState? state) {
|
||||||
|
EventHandler<XMLParsingState?> eh = NewState;
|
||||||
|
eh?.Invoke(this, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnConfigReload() {
|
||||||
|
EventHandler eh = ConfigReload;
|
||||||
|
eh?.Invoke(this, System.EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnNewData() {
|
||||||
|
EventHandler eh = NewData;
|
||||||
|
eh?.Invoke(this, System.EventArgs.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.5.001.0
|
VisualStudioVersion = 17.5.002.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HaWeb", "HaWeb.csproj", "{3FDCF678-C8B9-410D-8229-BEB69195D27C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HaWeb", "HaWeb.csproj", "{28D3D672-B38C-4E7F-B4A1-B9E7A930339E}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -11,15 +11,15 @@ Global
|
|||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{3FDCF678-C8B9-410D-8229-BEB69195D27C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{28D3D672-B38C-4E7F-B4A1-B9E7A930339E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{3FDCF678-C8B9-410D-8229-BEB69195D27C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{28D3D672-B38C-4E7F-B4A1-B9E7A930339E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3FDCF678-C8B9-410D-8229-BEB69195D27C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{28D3D672-B38C-4E7F-B4A1-B9E7A930339E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{3FDCF678-C8B9-410D-8229-BEB69195D27C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{28D3D672-B38C-4E7F-B4A1-B9E7A930339E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {7ED50D02-358C-467B-AB41-CF0F0D6D1627}
|
SolutionGuid = {E7A01088-1E90-40A0-B7C3-248918D6FFB2}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ public class FileModel {
|
|||||||
|
|
||||||
public void Log(string msg) {
|
public void Log(string msg) {
|
||||||
if (_log == null) _log = new StringBuilder();
|
if (_log == null) _log = new StringBuilder();
|
||||||
var prefix = DateTime.Now.ToShortTimeString() + " ";
|
_log.AppendLine(msg);
|
||||||
if (File != null) prefix += File.Name + ": ";
|
|
||||||
_log.AppendLine(prefix + msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetLog() {
|
public void ResetLog() {
|
||||||
|
|||||||
9
HaWeb/Models/GitState.cs
Normal file
9
HaWeb/Models/GitState.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using HaWeb.Models;
|
||||||
|
|
||||||
|
|
||||||
|
public class GitState {
|
||||||
|
public string Commit { get; set; }
|
||||||
|
public string Branch { get; set; }
|
||||||
|
public string URL { get; set; }
|
||||||
|
public DateTime PullTime { get; set; }
|
||||||
|
}
|
||||||
@@ -2,10 +2,12 @@ namespace HaWeb.Models;
|
|||||||
|
|
||||||
public class SyntaxCheckModel {
|
public class SyntaxCheckModel {
|
||||||
public string File { get; private set; }
|
public string File { get; private set; }
|
||||||
|
public string Commit { get; private set; }
|
||||||
public List<SyntaxError>? Errors { get; private set; }
|
public List<SyntaxError>? Errors { get; private set; }
|
||||||
|
|
||||||
public SyntaxCheckModel(string file) {
|
public SyntaxCheckModel(string file, string commithash) {
|
||||||
File = file;
|
File = file;
|
||||||
|
Commit = commithash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Log(int? line, int? column, string msg) {
|
public void Log(int? line, int? column, string msg) {
|
||||||
@@ -15,6 +17,11 @@ public class SyntaxCheckModel {
|
|||||||
Errors.Add(new SyntaxError(line, column, msg));
|
Errors.Add(new SyntaxError(line, column, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SortErrors() {
|
||||||
|
if (Errors != null)
|
||||||
|
Errors = Errors.OrderBy(x => x.Line).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public void ResetLog() {
|
public void ResetLog() {
|
||||||
Errors = null;
|
Errors = null;
|
||||||
}
|
}
|
||||||
|
|||||||
13
HaWeb/Models/XMLParsingState.cs
Normal file
13
HaWeb/Models/XMLParsingState.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace HaWeb.Models;
|
||||||
|
|
||||||
|
public class XMLParsingState : EventArgs {
|
||||||
|
internal List<FileModel>? ManagedFiles { get; set; }
|
||||||
|
internal Dictionary<string, FileList?>? Loaded { get; set; }
|
||||||
|
internal bool ValidState { get; set; }
|
||||||
|
|
||||||
|
public XMLParsingState() {
|
||||||
|
ManagedFiles = new();
|
||||||
|
Loaded = new();
|
||||||
|
ValidState = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,12 +7,9 @@ public class XMLStateViewModel {
|
|||||||
// Titel der Seite / Aktiver Präfix
|
// Titel der Seite / Aktiver Präfix
|
||||||
public string ActiveTitle { get; private set; }
|
public string ActiveTitle { get; private set; }
|
||||||
public IFileInfo? ActiveFile { get; set; }
|
public IFileInfo? ActiveFile { get; set; }
|
||||||
public (DateTime PullTime, string Hash)? GitData { get; private set; }
|
public GitState? GitData { get; private set; }
|
||||||
public bool ValidState { get; private set; }
|
public bool ValidState { get; private set; }
|
||||||
|
|
||||||
// Verfügbare Datei-Typen
|
|
||||||
public List<IXMLRoot>? AvailableRoots { get; private set; }
|
|
||||||
|
|
||||||
// Akuell geladene Dateien
|
// Akuell geladene Dateien
|
||||||
public List<FileModel>? ManagedFiles { get; private set; }
|
public List<FileModel>? ManagedFiles { get; private set; }
|
||||||
|
|
||||||
@@ -24,13 +21,11 @@ public class XMLStateViewModel {
|
|||||||
|
|
||||||
public XMLStateViewModel(
|
public XMLStateViewModel(
|
||||||
string title,
|
string title,
|
||||||
(DateTime PullTime, string Hash)? gitData,
|
GitState? gitData,
|
||||||
List<IXMLRoot>? roots,
|
|
||||||
List<IFileInfo>? hamannFiles,
|
List<IFileInfo>? hamannFiles,
|
||||||
List<FileModel>? managedFiles,
|
List<FileModel>? managedFiles,
|
||||||
bool validState) {
|
bool validState) {
|
||||||
ActiveTitle = title;
|
ActiveTitle = title;
|
||||||
AvailableRoots = roots;
|
|
||||||
HamannFiles = hamannFiles;
|
HamannFiles = hamannFiles;
|
||||||
ManagedFiles = managedFiles;
|
ManagedFiles = managedFiles;
|
||||||
GitData = gitData;
|
GitData = gitData;
|
||||||
|
|||||||
@@ -35,11 +35,13 @@ var XMLFP = new XMLFileProvider(XMLIS, hdW, builder.Configuration);
|
|||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
builder.Services.AddTransient<IReaderService, ReaderService>();
|
|
||||||
builder.Services.AddSingleton<IXMLTestService, XMLTestService>((_) => tS);
|
builder.Services.AddSingleton<IXMLTestService, XMLTestService>((_) => tS);
|
||||||
builder.Services.AddSingleton<IXMLInteractionService, XMLInteractionService>((_) => XMLIS);
|
builder.Services.AddSingleton<IXMLInteractionService, XMLInteractionService>((_) => XMLIS);
|
||||||
builder.Services.AddSingleton<IHaDocumentWrappper, HaDocumentWrapper>((_) => hdW);
|
builder.Services.AddSingleton<IHaDocumentWrappper, HaDocumentWrapper>((_) => hdW);
|
||||||
builder.Services.AddSingleton<IXMLFileProvider, XMLFileProvider>(_ => XMLFP);
|
builder.Services.AddSingleton<IXMLFileProvider, XMLFileProvider>(_ => XMLFP);
|
||||||
|
builder.Services.AddSingleton<WebSocketMiddleware>();
|
||||||
|
builder.Services.AddTransient<IReaderService, ReaderService>();
|
||||||
|
|
||||||
// builder.Services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();
|
// builder.Services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();
|
||||||
// builder.Services.AddHostedService<QueuedHostedService>();
|
// builder.Services.AddHostedService<QueuedHostedService>();
|
||||||
// builder.Services.AddSingleton<IBackgroundTaskQueue>(ctx =>
|
// builder.Services.AddSingleton<IBackgroundTaskQueue>(ctx =>
|
||||||
@@ -60,6 +62,11 @@ ChangeToken.OnChange(
|
|||||||
app.Environment
|
app.Environment
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.UseWebSockets( new WebSocketOptions {
|
||||||
|
KeepAliveInterval = TimeSpan.FromMinutes(180)
|
||||||
|
});
|
||||||
|
app.UseMiddleware<WebSocketMiddleware>();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (!app.Environment.IsDevelopment())
|
if (!app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ Run
|
|||||||
|
|
||||||
`dotnet watch run` and
|
`dotnet watch run` and
|
||||||
|
|
||||||
`npm run watch`
|
`npm run watch` or
|
||||||
|
|
||||||
|
`bun run watch`
|
||||||
|
|
||||||
in seperate terminals to watch for specific file changes in .css / .js / .cshtml / .json or .cs files and to rebuild the css-Files and the app automatically on change.
|
in seperate terminals to watch for specific file changes in .css / .js / .cshtml / .json or .cs files and to rebuild the css-Files and the app automatically on change.
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ Recommended vscode plugins include the XML Tools, c#, Tailwind CSS IntelliSense
|
|||||||
|
|
||||||
## Release
|
## Release
|
||||||
|
|
||||||
To build a release version for the current server, run:
|
To build a release version for the current server, build the css file, then run:
|
||||||
|
|
||||||
`dotnet publish -a x64 --os win -c Release`
|
`dotnet publish -a x64 --os win -c Release`
|
||||||
|
|
||||||
@@ -99,4 +101,35 @@ KOmmentare verschobem 202 Anhang
|
|||||||
|
|
||||||
Known Bugs:
|
Known Bugs:
|
||||||
- click event does not work in iOS
|
- click event does not work in iOS
|
||||||
- rerender marginals on tab switch
|
- rerender marginals on tab switch
|
||||||
|
|
||||||
|
|
||||||
|
GIT-UMBAU:
|
||||||
|
|
||||||
|
- OPUS-Check briefe
|
||||||
|
- SYNTAX-Check
|
||||||
|
- ILIB
|
||||||
|
(- Searchables)
|
||||||
|
|
||||||
|
Start: kein background service
|
||||||
|
Datei vom Admin-Panel laden: kein bacckground service
|
||||||
|
Datei ändert sich: background service + reload call on all clients
|
||||||
|
Konfiguration ändert sich: kein background service
|
||||||
|
|
||||||
|
BACKGROUND SERVICE:
|
||||||
|
- FileWatch
|
||||||
|
- XMLInteractionService.Collect(List<IFileInfo>)
|
||||||
|
- XMLInteractionService.TryCreate()
|
||||||
|
- XMLFileProvider.SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary? ModelState)
|
||||||
|
|
||||||
|
BACKGROUND SERVICE WITH JSON OUTPUT:
|
||||||
|
- XMLTestService.Test(XMLInteractionService)
|
||||||
|
|
||||||
|
KEIN BACKGROUND SERVICE:
|
||||||
|
- HaDocuemntWrapper.SetLibrary(IFileInfo? file, XDocument? doc, ModelStateDictionary? ModelState = null)
|
||||||
|
- XMLInteractionService.CreateSearchables(XDocument document)
|
||||||
|
|
||||||
|
TASKS:
|
||||||
|
- Syntax Errors nicht mehr im FileModel loggen
|
||||||
|
- State für Collect()
|
||||||
|
- State für TryCreate()
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ namespace HaWeb;
|
|||||||
public static class Features {
|
public static class Features {
|
||||||
// If Admin Pages are reachable
|
// If Admin Pages are reachable
|
||||||
public const string AdminService = "AdminService";
|
public const string AdminService = "AdminService";
|
||||||
// If the Upload of files is possible, also syntaxcheck and crossreference check
|
|
||||||
public const string UploadService = "UploadService";
|
|
||||||
// If uploaded Files can be published locally
|
// If uploaded Files can be published locally
|
||||||
public const string LocalPublishService = "LocalPublishService";
|
public const string LocalPublishService = "LocalPublishService";
|
||||||
// If this server can publish files remotely (e.g. www.hamann-ausgabe.de)
|
// If this Server can run a SyntaxCheck
|
||||||
public const string RemotePublishService = "RemotePublishService";
|
public const string SyntaxCheck = "SyntaxCheck";
|
||||||
// If this server can accept files from a remote authenticated source
|
// If this Server shows live notifications & reload
|
||||||
public const string RemotePublishSourceService = "RemotePublishSourceService";
|
public const string Notifications = "Notifications";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web" DefaultTargets="Tailwind">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<EnablePreviewFeatures>True</EnablePreviewFeatures>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Remove="wwwroot\css\output.css" />
|
|
||||||
<Content Include="wwwroot\css\output.css" Watch="false" />
|
|
||||||
<Content Remove="**\*.cs" />
|
|
||||||
<Content Include="**\*.cs" Watch="false" />
|
|
||||||
<Content Remove="Settings\CSSClassesSettings.cs" />
|
|
||||||
<Content Include="Settings\CSSClassesSettings.cs" Watch="true" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Target Name="Tailwind" BeforeTargets="Build">
|
|
||||||
<Exec Command="npm run css_build" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\HaXMLReaderV6\HaXMLReaderV6.csproj" />
|
|
||||||
<ProjectReference Include="..\HaDocumentV6\HaDocumentV6.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="2.5.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -5,57 +5,137 @@
|
|||||||
ViewData["showCredits"] = "false";
|
ViewData["showCredits"] = "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="ha-adminuploadfields" id="ha-adminuploadfields">
|
@* TODO: Headers <div class="ha-xmlstateheader">
|
||||||
<div class="ha-uploadcontainer">
|
<h1>XML-Daten</h1>
|
||||||
|
</div> *@
|
||||||
@* File Category Page File List *@
|
|
||||||
@*
|
|
||||||
<textarea class="py-2 px-3 mx-8 mb-8 shadow-lg font-mono text-sm border rounded" id="errormessagebox" name="errormessagebox" rows="25" cols="90" readonly>
|
|
||||||
@foreach (var f in Model.Files[Model.Prefix])
|
|
||||||
{
|
|
||||||
@f.Messages
|
|
||||||
}
|
|
||||||
</textarea> *@
|
|
||||||
@if (Model.ManagedFiles != null && Model.ManagedFiles.Any()) {
|
@if (Model.ManagedFiles != null && Model.ManagedFiles.Any()) {
|
||||||
<div class="">
|
<div class="ha-managedfiles">
|
||||||
<table>
|
<div class="ha-repo">
|
||||||
@foreach (var f in Model.ManagedFiles) {
|
<div class="ha-repodata">
|
||||||
<tr>
|
<div><a href="https://github.com/Theodor-Springmann-Stiftung/hamann-xml">Repository →</a></div>
|
||||||
<td>@f.FileName</td>
|
@if (Model.GitData != null) {
|
||||||
<td>@f.GetLastModified()</td>
|
<div>Commit @Model.GitData.Commit.Substring(0,7)</div>
|
||||||
@if (f.IsValid) {
|
<div>@Model.GitData.PullTime</div>
|
||||||
<td>Valid! @f.GetLog()</td>
|
}
|
||||||
<td>
|
</div>
|
||||||
@if (Model.SyntaxCheck[f.FileName] != null && Model.SyntaxCheck[f.FileName].Errors != null) {
|
<div class="ha-repofilecount">
|
||||||
<ul>
|
@Model.ManagedFiles.Count XML-Dateien
|
||||||
@foreach(var e in Model.SyntaxCheck[f.FileName]?.Errors) {
|
</div>
|
||||||
<li>@e.Line @e.Column @e.Message </li>
|
</div>
|
||||||
}
|
|
||||||
</ul>
|
@* Syntax-Check cached? We provide the results. *@
|
||||||
}
|
@if (Model.SyntaxCheck != null) {
|
||||||
</td>
|
<div class="ha-managedfileslist">
|
||||||
} else {
|
@foreach (var f in Model.ManagedFiles) {
|
||||||
<td>@f.GetLog()</td>
|
<div class="ha-managedfile" id="@f.FileName">
|
||||||
<td> </td>
|
@if (Model.SyntaxCheck.ContainsKey(f.FileName) && Model.SyntaxCheck[f.FileName].Errors == null) {
|
||||||
}
|
<div class="ha-managedfileheader green">
|
||||||
</tr>
|
<div>@f.FileName</div>
|
||||||
|
<div>@f.GetLastModified()</div>
|
||||||
|
<div class="ha-filestatusicon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>check-bold</title><path fill="currentColor" d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" /></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} else if (Model.SyntaxCheck.ContainsKey(f.FileName)) {
|
||||||
|
<div class="ha-managedfileheader expandable orange">
|
||||||
|
<div>@f.FileName</div>
|
||||||
|
<div>@f.GetLastModified()</div>
|
||||||
|
<div class="ha-filestatusicon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>alert-decagram-outline</title><path d="M23,12L20.56,14.78L20.9,18.46L17.29,19.28L15.4,22.46L12,21L8.6,22.47L6.71,19.29L3.1,18.47L3.44,14.78L1,12L3.44,9.21L3.1,5.53L6.71,4.72L8.6,1.54L12,3L15.4,1.54L17.29,4.72L20.9,5.54L20.56,9.22L23,12M20.33,12L18.5,9.89L18.74,7.1L16,6.5L14.58,4.07L12,5.18L9.42,4.07L8,6.5L5.26,7.09L5.5,9.88L3.67,12L5.5,14.1L5.26,16.9L8,17.5L9.42,19.93L12,18.81L14.58,19.92L16,17.5L18.74,16.89L18.5,14.1L20.33,12M11,15H13V17H11V15M11,7H13V13H11V7" /></svg> </div>
|
||||||
|
</div>
|
||||||
|
<div class="ha-managedfileannotations">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Zeile</th>
|
||||||
|
<th>Spalte</th>
|
||||||
|
<th>Fehler</th>
|
||||||
|
</tr>
|
||||||
|
@foreach (var e in Model.SyntaxCheck[f.FileName]!.Errors) {
|
||||||
|
<tr>
|
||||||
|
<td>@e.Line</td>
|
||||||
|
<td>@e.Column</td>
|
||||||
|
<td>@e.Message</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
} else {
|
||||||
|
<div class="ha-managedfileheader expandable expanded red">
|
||||||
|
<div>@f.FileName</div>
|
||||||
|
<div>@f.GetLastModified()</div>
|
||||||
|
<div class="ha-filestatusicon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>close-thick</title><path d="M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z" /></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ha-managedfileannotations">
|
||||||
|
@f.GetLog()
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@* No SyntaxCheck? We provide the data + a button to load *@
|
||||||
|
else {
|
||||||
|
<div class="ha-managedfileslist">
|
||||||
|
@foreach (var f in Model.ManagedFiles) {
|
||||||
|
<div class="ha-managedfile" id="@f.FileName">
|
||||||
|
@if (f.IsValid) {
|
||||||
|
<div class="ha-managedfileheader">
|
||||||
|
<div>@f.FileName</div>
|
||||||
|
<div>@f.GetLastModified()</div>
|
||||||
|
<div class="ha-filestatusicon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>check-bold</title><path fill="currentColor" d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" /></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} else {
|
||||||
|
<div class="ha-managedfileheader expandable expanded red">
|
||||||
|
<div>@f.FileName</div>
|
||||||
|
<div>@f.GetLastModified()</div>
|
||||||
|
<div class="ha-filestatusicon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>close-thick</title><path d="M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z" /></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="ha-managedfileannotations">
|
||||||
|
@f.GetLog()
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<feature name="SyntaxCheck">
|
||||||
|
@if (Model.ValidState) {
|
||||||
|
<form class="ha-selectfilesform" asp-controller="API" asp-action="GetSyntaxCheck" onsubmit="GETSyntaxCheck(this);return false;" method="get">
|
||||||
|
<button type="submit" class="ha-scbutton" id="ha-scbutton" >
|
||||||
|
Verweise & IDs prüfen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
</table>
|
</feature>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
} else {
|
} else {
|
||||||
<div class="">
|
|
||||||
|
<div class="ha-managedfilesnotfound">
|
||||||
Keine Dateien im Repository gefunden!
|
Keine Dateien im Repository gefunden!
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<feature name="LocalPublishService">
|
||||||
<script defer src="/js/filelistform.js" asp-append-version="true"></script>
|
<div class="ha-filelistfieldset">
|
||||||
|
<div class="ha-filelistlegend">Auswahl verfügbarer Dateien</div>
|
||||||
<fieldset class="ha-filelistfieldset">
|
|
||||||
<legend class="ha-filelistlegend">Verfügbare Dateien</legend>
|
|
||||||
@if(Model.HamannFiles != null && Model.HamannFiles.Any()) {
|
@if(Model.HamannFiles != null && Model.HamannFiles.Any()) {
|
||||||
<form class="ha-selectfilesform" id="selecthamannfilesform" asp-controller="API" asp-action="SetInProduction" method="post" onsubmit="USESubmit(this);return false;" enctype="multipart/form-data">
|
<form class="ha-selectfilesform" id="selecthamannfilesform" asp-controller="API" asp-action="SetInProduction" method="post" onsubmit="USESubmit(this);return false;" enctype="application/x-www-form-urlencoded">
|
||||||
<div class="ha-filelistlist">
|
<div class="ha-filelistlist">
|
||||||
|
@if (!Model.ValidState) {
|
||||||
|
<div class="ha-filelistfile">
|
||||||
|
<input type="radio" disabled><div class="ha-filelistname"> Aktuelle Datei kann nicht geladen werden.</div>
|
||||||
|
<div class="ha-filelistusedproduction">
|
||||||
|
<div class="ha-filelistproduction hue-rotate-180">Fehler</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@foreach (var file in Model.HamannFiles) {
|
@foreach (var file in Model.HamannFiles) {
|
||||||
<div class="ha-filelistfile">
|
<div class="ha-filelistfile">
|
||||||
@if (Model.ActiveFile != null) {
|
@if (Model.ActiveFile != null) {
|
||||||
@@ -66,7 +146,7 @@
|
|||||||
<div class="ha-filelistname">@file.Name</div>
|
<div class="ha-filelistname">@file.Name</div>
|
||||||
@if (Model.ActiveFile != null && file.Name == Model.ActiveFile!.Name) {
|
@if (Model.ActiveFile != null && file.Name == Model.ActiveFile!.Name) {
|
||||||
<div class="ha-filelistusedproduction">
|
<div class="ha-filelistusedproduction">
|
||||||
<div class="ha-filelistproduction">in Verwendung</div>
|
<div class="ha-filelistproduction">geladen</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@* // TODO Metadata
|
@* // TODO Metadata
|
||||||
@@ -75,11 +155,6 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@if (!Model.ValidState) {
|
|
||||||
<div>
|
|
||||||
Status nicht validiert! Daten können nicht auf der Webseite angezeigt werden!
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<output id ="ha-filelistoutput"></output>
|
<output id ="ha-filelistoutput"></output>
|
||||||
<button type="submit" class="ha-filelistbutton" id="ha-filelistbutton" >
|
<button type="submit" class="ha-filelistbutton" id="ha-filelistbutton" >
|
||||||
Laden
|
Laden
|
||||||
@@ -90,4 +165,6 @@
|
|||||||
else {
|
else {
|
||||||
<div>Keine Dateien gefunden! Es wird eine fallback-Datei verwendet!</div>
|
<div>Keine Dateien gefunden! Es wird eine fallback-Datei verwendet!</div>
|
||||||
}
|
}
|
||||||
</fieldset>
|
</div>
|
||||||
|
</feature>
|
||||||
|
<script defer src="/js/filelistform.js" asp-append-version="true"></script>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<div class="ha-comment">
|
<div class="ha-comment">
|
||||||
<div class="ha-headcomment">
|
<div class="ha-headcomment">
|
||||||
<div class="ha-commentmetatext">
|
<div class="ha-commentmetatext">
|
||||||
Briefe von und an  
|
Briefwechsel mit  
|
||||||
<a class="ha-reversefilter" asp-controller="Index" asp-action="Index">← Alle Briefe</a>
|
<a class="ha-reversefilter" asp-controller="Index" asp-action="Index">← Alle Briefe</a>
|
||||||
</div>
|
</div>
|
||||||
@Html.Raw(Model.PersonComment.ParsedComment)
|
@Html.Raw(Model.PersonComment.ParsedComment)
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (Model.ActivePerson != null && Model.AvailablePersons.Where(x => x.Key == Model.ActivePerson).Any()) {
|
@if (Model.ActivePerson != null && Model.AvailablePersons.Where(x => x.Key == Model.ActivePerson).Any()) {
|
||||||
<div class="ha-activefilterinfo">
|
<div class="ha-activefilterinfo">
|
||||||
Briefe von und an @Model.AvailablePersons.Where(x => x.Key == Model.ActivePerson).First().Name. 
|
Briefwechsel mit @Model.AvailablePersons.Where(x => x.Key == Model.ActivePerson).First().Name. 
|
||||||
<a class="ha-reversefilter" asp-controller="Index" asp-action="Index">← Auswahl aufheben</a>
|
<a class="ha-reversefilter" asp-controller="Index" asp-action="Index">← Auswahl aufheben</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@await Html.PartialAsync("/Views/Shared/_ScrollButton.cshtml")
|
@await Html.PartialAsync("/Views/Shared/_ScrollButton.cshtml")
|
||||||
|
<feature name="Notifications">
|
||||||
|
@await Html.PartialAsync("/Views/Shared/_Notifications.cshtml")
|
||||||
|
</feature>
|
||||||
@await RenderSectionAsync("JavaScript", false)
|
@await RenderSectionAsync("JavaScript", false)
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
@* Global Scripts -- These are not inside .cshtml to not loose deferred execution posibility *@
|
@* Global Scripts -- These are not inside .cshtml to not loose deferred execution posibility *@
|
||||||
|
<feature name="Notifications">
|
||||||
|
<script defer src="/js/websocket.js" asp-append-version="true"></script>
|
||||||
|
</feature>
|
||||||
|
<script defer src="/js/marginals.js" asp-append-version="true"></script>
|
||||||
<script defer src="/js/theme.js" asp-append-version="true"></script>
|
<script defer src="/js/theme.js" asp-append-version="true"></script>
|
||||||
<script defer src="/js/active.js" asp-append-version="true"></script>
|
<script defer src="/js/active.js" asp-append-version="true"></script>
|
||||||
<script defer src="/js/anchor.js" asp-append-version="true"></script>
|
<script defer src="/js/anchor.js" asp-append-version="true"></script>
|
||||||
<script defer src="/js/marginals.js" asp-append-version="true"></script>
|
|
||||||
<script defer src="/js/mobilemenu.js" asp-append-version="true"></script>
|
<script defer src="/js/mobilemenu.js" asp-append-version="true"></script>
|
||||||
<script defer src="/js/scrollbutton.js" asp-append-version="true"></script>
|
<script defer src="/js/scrollbutton.js" asp-append-version="true"></script>
|
||||||
<script defer src="/js/clipboard.js" asp-append-version="true"></script>
|
<script defer src="/js/clipboard.js" asp-append-version="true"></script>
|
||||||
|
|||||||
9
HaWeb/Views/Shared/_Notifications.cshtml
Normal file
9
HaWeb/Views/Shared/_Notifications.cshtml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<div class="ha-notifications" id="comm-notifications">
|
||||||
|
<div class="ha-notcontent">
|
||||||
|
<div class="ha-commslog" id="commsLog"></div>
|
||||||
|
<div class="ha-noticon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 640 512"><!--! Font Awesome Free 6.4.2 by fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 336c0 79.5 64.5 144 144 144H512c70.7 0 128-57.3 128-128c0-61.9-44-113.6-102.4-125.4c4.1-10.7 6.4-22.4 6.4-34.6c0-53-43-96-96-96c-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32C167.6 32 96 103.6 96 192c0 2.7 .1 5.4 .2 8.1C40.2 219.8 0 273.2 0 336z"/></svg>
|
||||||
|
@* <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>circle-small</title><path d="M12,10A2,2 0 0,0 10,12C10,13.11 10.9,14 12,14C13.11,14 14,13.11 14,12A2,2 0 0,0 12,10Z" /></svg> *@
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
126
HaWeb/WebSockets/WebSocketMiddleware.cs
Normal file
126
HaWeb/WebSockets/WebSocketMiddleware.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using HaWeb;
|
||||||
|
using HaWeb.FileHelpers;
|
||||||
|
using HaWeb.Models;
|
||||||
|
using HaWeb.XMLParser;
|
||||||
|
using Microsoft.FeatureManagement;
|
||||||
|
|
||||||
|
public class WebSocketMiddleware : IMiddleware {
|
||||||
|
internal enum ValidationState {
|
||||||
|
False,
|
||||||
|
Parsing,
|
||||||
|
True
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FileState {
|
||||||
|
public ValidationState ValidationState { get; private set; }
|
||||||
|
|
||||||
|
public FileState(ValidationState state) {
|
||||||
|
this.ValidationState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileState(XMLParsingState? state) {
|
||||||
|
if (state == null) ValidationState = ValidationState.Parsing;
|
||||||
|
else if (state.ValidState == true) ValidationState = ValidationState.True;
|
||||||
|
else ValidationState = ValidationState.False;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IFeatureManager _featureManager;
|
||||||
|
private readonly IXMLInteractionService _xmlService;
|
||||||
|
private readonly IXMLFileProvider _xmlProvider;
|
||||||
|
|
||||||
|
private List<WebSocket>? _openSockets;
|
||||||
|
|
||||||
|
public WebSocketMiddleware(IXMLFileProvider xmlprovider, IXMLInteractionService xmlservice, IFeatureManager featuremanager){
|
||||||
|
this._xmlProvider = xmlprovider;
|
||||||
|
this._xmlService = xmlservice;
|
||||||
|
this._featureManager = featuremanager;
|
||||||
|
if (_openSockets == null) _openSockets = new List<WebSocket>();
|
||||||
|
_Subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InvokeAsync(HttpContext context, RequestDelegate requestDelegate) {
|
||||||
|
if (!context.WebSockets.IsWebSocketRequest || context.Request.Path != "/WS") {
|
||||||
|
// this case works perfectly fine for regular REST, middleware gets called.
|
||||||
|
await requestDelegate.Invoke(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await _featureManager.IsEnabledAsync(Features.Notifications)) {
|
||||||
|
using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync()) {
|
||||||
|
await HandleConnection(context, webSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _Subscribe() {
|
||||||
|
_xmlProvider.FileChange += _HandleFileChange;
|
||||||
|
_xmlProvider.NewState += _HandleNewState;
|
||||||
|
_xmlProvider.NewData += _HandleNewData;
|
||||||
|
_xmlProvider.ConfigReload += _HandleConfigReload;
|
||||||
|
_xmlService.SyntaxCheck += _HandleSyntaxCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleConnection(HttpContext context, WebSocket webSocket) {
|
||||||
|
var buffer = new byte[1024 * 4];
|
||||||
|
_openSockets!.Add(webSocket);
|
||||||
|
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
while (!result.CloseStatus.HasValue) {
|
||||||
|
var state = _xmlProvider.GetGitState();
|
||||||
|
await webSocket.SendAsync(_SerializeToBytes(state), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
await webSocket.SendAsync(_SerializeToBytes(new FileState(_xmlService.GetState())), result.MessageType, true, CancellationToken.None);
|
||||||
|
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
}
|
||||||
|
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||||
|
_openSockets!.Remove(webSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void _HandleFileChange(object? sender, GitState? state) {
|
||||||
|
await _SendToAll(state);
|
||||||
|
await _SendToAll(new FileState(ValidationState.Parsing));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void _HandleNewState(object? sender, XMLParsingState? state) {
|
||||||
|
if (state == null || !state.ValidState)
|
||||||
|
await _SendToAll(new FileState(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void _HandleNewData(object? sender, EventArgs _) {
|
||||||
|
await _SendToAll(new { reload = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void _HandleConfigReload(object? sender, EventArgs _) {
|
||||||
|
await _SendToAll(new { configreload = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void _HandleSyntaxCheck(object? sender, Dictionary<string, SyntaxCheckModel>? state) {
|
||||||
|
if (state != null && state.Any()) {
|
||||||
|
foreach (var c in state)
|
||||||
|
if (c.Value.Errors != null) {
|
||||||
|
await _SendToAll(new { SC = false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await _SendToAll(new { SC = true });
|
||||||
|
}
|
||||||
|
await _SendToAll(new { SC = (String?)null });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _SendToAll<T>(T msg) {
|
||||||
|
if (_openSockets == null) return;
|
||||||
|
foreach (var socket in _openSockets) {
|
||||||
|
await socket.SendAsync(_SerializeToBytes(msg), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArraySegment<byte> _SerializeToBytes<T>(T o) {
|
||||||
|
var json = JsonSerializer.Serialize<T>(o);
|
||||||
|
if (String.IsNullOrWhiteSpace(json)) {
|
||||||
|
return new ArraySegment<byte>(new byte[] { }, 0, 0);
|
||||||
|
}
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(json);
|
||||||
|
return new ArraySegment<byte>(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,15 +8,18 @@ using HaXMLReader.Interfaces;
|
|||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
|
|
||||||
public interface IXMLInteractionService {
|
public interface IXMLInteractionService {
|
||||||
public XElement? TryCreate();
|
public event EventHandler<Dictionary<string, SyntaxCheckModel>?> SyntaxCheck;
|
||||||
public bool GetValidState();
|
public XElement? TryCreate(XMLParsingState? state);
|
||||||
public void Collect(List<IFileInfo> Files);
|
public XMLParsingState? GetState();
|
||||||
public Dictionary<string, FileList?>? GetLoaded();
|
public void SetState(XMLParsingState? state);
|
||||||
public IXMLRoot? GetRoot(string name);
|
public Dictionary<string, IXMLRoot>? GetRootDefs();
|
||||||
public List<IXMLRoot>? GetRootsList();
|
public Dictionary<string, SyntaxCheckModel>? GetSCCache();
|
||||||
public void CreateSearchables(XDocument document);
|
public void SetSCCache(Dictionary<string, SyntaxCheckModel>? cache);
|
||||||
public List<FileModel>? GetManagedFiles();
|
public XMLParsingState? Collect(List<IFileInfo> Files, Dictionary<string, IXMLRoot>? rootDefs); // XMLFileProvider
|
||||||
public Dictionary<string, SyntaxCheckModel>? Test();
|
public void CreateSearchables(XDocument document); // XMLFileProvider
|
||||||
|
public Dictionary<string, SyntaxCheckModel>? Test(XMLParsingState? state, string gitcommit); // XMLFileProvider (optimal), Controller (right now)
|
||||||
|
// Controller
|
||||||
public List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? SearchCollection(string collection, string searchword, IReaderService reader, ILibrary? lib);
|
public List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? SearchCollection(string collection, string searchword, IReaderService reader, ILibrary? lib);
|
||||||
|
// Controller
|
||||||
public List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? GetPreviews(List<(string, List<Marginal>)> places, IReaderService reader, ILibrary lib);
|
public List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? GetPreviews(List<(string, List<Marginal>)> places, IReaderService reader, ILibrary lib);
|
||||||
}
|
}
|
||||||
@@ -36,12 +36,13 @@ public class XMLInteractionService : IXMLInteractionService {
|
|||||||
|
|
||||||
private Dictionary<string, IXMLRoot>? _RootDefs;
|
private Dictionary<string, IXMLRoot>? _RootDefs;
|
||||||
private Dictionary<string, IXMLCollection>? _CollectionDefs;
|
private Dictionary<string, IXMLCollection>? _CollectionDefs;
|
||||||
|
|
||||||
private List<FileModel>? _ManagedFiles;
|
|
||||||
private Dictionary<string, FileList?>? _Loaded;
|
|
||||||
private Dictionary<string, ItemsCollection>? _Collection;
|
private Dictionary<string, ItemsCollection>? _Collection;
|
||||||
|
|
||||||
private bool _ValidState = false;
|
public event EventHandler<Dictionary<string, SyntaxCheckModel>?> SyntaxCheck;
|
||||||
|
|
||||||
|
private XMLParsingState? _State;
|
||||||
|
|
||||||
|
private Dictionary<string, SyntaxCheckModel>? _SCCache;
|
||||||
|
|
||||||
public XMLInteractionService(IConfiguration config, IXMLTestService testService) {
|
public XMLInteractionService(IConfiguration config, IXMLTestService testService) {
|
||||||
_testService = testService;
|
_testService = testService;
|
||||||
@@ -68,38 +69,30 @@ public class XMLInteractionService : IXMLInteractionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
public Dictionary<string, FileList?>? GetLoaded() => this._Loaded;
|
public XMLParsingState? GetState() => this._State;
|
||||||
|
|
||||||
public List<FileModel>? GetManagedFiles() => this._ManagedFiles;
|
public void SetState(XMLParsingState? state) => this._State = state;
|
||||||
|
|
||||||
public List<IXMLRoot>? GetRootsList() => this._RootDefs == null ? null : this._RootDefs.Values.ToList();
|
public Dictionary<string, IXMLRoot>? GetRootDefs() => this._RootDefs;
|
||||||
|
|
||||||
public bool GetValidState() => this._ValidState;
|
public Dictionary<string, SyntaxCheckModel>? GetSCCache() => this._SCCache;
|
||||||
|
|
||||||
public IXMLRoot? GetRoot(string name) {
|
public void SetSCCache(Dictionary<string, SyntaxCheckModel>? cache) => this._SCCache = cache;
|
||||||
if (_RootDefs == null) return null;
|
|
||||||
_RootDefs.TryGetValue(name, out var root);
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
public void Collect(List<IFileInfo> files) {
|
public XMLParsingState? Collect(List<IFileInfo> files, Dictionary<string, IXMLRoot>? rootDefs) {
|
||||||
if (files == null || !files.Any()) return;
|
if (files == null || !files.Any() || rootDefs == null || !rootDefs.Any()) return null;
|
||||||
_ValidState = true;
|
var _state = new XMLParsingState() {
|
||||||
Dictionary<string, FileList?>? lF = new Dictionary<string, FileList?>();
|
ValidState = true
|
||||||
List<FileModel> fM = new List<FileModel>();
|
};
|
||||||
foreach (var f in files) {
|
foreach (var f in files) {
|
||||||
var sb = new StringBuilder();
|
|
||||||
var m = _CreateFileModel(f, null);
|
var m = _CreateFileModel(f, null);
|
||||||
fM.Add(m);
|
_state.ManagedFiles!.Add(m);
|
||||||
// 1. Open File for Reading
|
// 1. Open File for Reading
|
||||||
try {
|
try {
|
||||||
using (Stream file = f.CreateReadStream()) {
|
using (Stream file = f.CreateReadStream()) {
|
||||||
// 2. Some security checks, if file empty, wrong start, wrong extension, too big
|
// 2. Some security checks, if file empty, wrong start, wrong extension, too big
|
||||||
if (!XMLFileHelpers.ProcessFile(file, f.Name, sb, _allowedExtensions, _fileSizeLimit)) {
|
if (!XMLFileHelpers.ProcessFile(file, f.Name, m.Log, _allowedExtensions, _fileSizeLimit)) continue;
|
||||||
m.Log(sb.ToString());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
m.Log( "Datei konnte nicht geöffnet werden.");
|
m.Log( "Datei konnte nicht geöffnet werden.");
|
||||||
@@ -113,14 +106,14 @@ public class XMLInteractionService : IXMLInteractionService {
|
|||||||
|
|
||||||
// 4. Check if opus-Document
|
// 4. Check if opus-Document
|
||||||
// TODO: Unter der HOOD werden in ProbeFiles noch eigene Files gebaut!
|
// TODO: Unter der HOOD werden in ProbeFiles noch eigene Files gebaut!
|
||||||
var docs = _ProbeFile(doc, m);
|
var docs = _ProbeFile(doc, m, rootDefs);
|
||||||
if (docs == null || !docs.Any()) continue;
|
if (docs == null || !docs.Any()) continue;
|
||||||
|
|
||||||
// Success! File can be recognized and parsed.
|
// Success! File can be recognized and parsed.
|
||||||
m.Validate();
|
m.Validate();
|
||||||
foreach (var d in docs) {
|
foreach (var d in docs) {
|
||||||
if (!lF.ContainsKey(d.Prefix)) lF.Add(d.Prefix, new FileList(d.XMLRoot));
|
if (!_state.Loaded!.ContainsKey(d.Prefix)) _state.Loaded.Add(d.Prefix, new FileList(d.XMLRoot));
|
||||||
lF[d.Prefix]!.Add(d);
|
_state.Loaded[d.Prefix]!.Add(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@@ -129,32 +122,38 @@ public class XMLInteractionService : IXMLInteractionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set data
|
foreach (var f in _state.ManagedFiles!) {
|
||||||
this._ManagedFiles = fM;
|
if (!f.IsValid) {
|
||||||
this._Loaded = lF;
|
_state.ValidState = false;
|
||||||
foreach (var f in _ManagedFiles) {
|
break;
|
||||||
if (!f.IsValid) this._ValidState = false;
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, SyntaxCheckModel>? Test() {
|
// Every caller shoud ask the cache above first
|
||||||
if (_Loaded == null) return null;
|
public Dictionary<string, SyntaxCheckModel>? Test(XMLParsingState? state, string gitcommit) {
|
||||||
|
if (state == null || state.Loaded == null) return null;
|
||||||
// TODO: Speed up this, move it into a background task:
|
// TODO: Speed up this, move it into a background task:
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var res = this._Loaded?.SelectMany(x => x.Value?.GetFileList()?.Select(x => x.File)).Distinct().Select(x => x.FileName);
|
var res = state.Loaded?.SelectMany(x => x.Value?.GetFileList()?.Select(x => x.File)).Distinct().Select(x => x.FileName);
|
||||||
var ret = _testService.Test(this._Loaded, res.ToDictionary(x => x, y => new SyntaxCheckModel(y)));
|
var ret = _testService.Test(state.Loaded, res.ToDictionary(x => x, y => new SyntaxCheckModel(y, gitcommit)));
|
||||||
|
if (ret != null)
|
||||||
|
foreach (var r in ret) {
|
||||||
|
r.Value.SortErrors();
|
||||||
|
}
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
Console.WriteLine("Syntaxcheck " + sw.ElapsedMilliseconds.ToString() + " ms");
|
Console.WriteLine("Syntaxcheck " + sw.ElapsedMilliseconds.ToString() + " ms");
|
||||||
|
OnSyntaxCheck(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public XElement? TryCreate() {
|
public XElement? TryCreate(XMLParsingState state) {
|
||||||
if (_Loaded == null || !_Loaded.Any() || _RootDefs == null || !_RootDefs.Any() || !_ValidState) return null;
|
if (state.Loaded == null || !state.Loaded.Any() || _RootDefs == null || !_RootDefs.Any() || !state.ValidState) return null;
|
||||||
var opus = new XElement("opus");
|
var opus = new XElement("opus");
|
||||||
// TODO: Workaround for bug in HaDocument: roots have to be added in a specific order
|
// TODO: Workaround for bug in HaDocument: roots have to be added in a specific order
|
||||||
var used = _Loaded.OrderByDescending(x => x.Key);
|
var used = state.Loaded.OrderByDescending(x => x.Key);
|
||||||
foreach (var category in used) {
|
foreach (var category in used) {
|
||||||
if (category.Value == null || category.Value.GetFileList() == null || !category.Value.GetFileList()!.Any()) {
|
if (category.Value == null || category.Value.GetFileList() == null || !category.Value.GetFileList()!.Any()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -302,15 +301,15 @@ public class XMLInteractionService : IXMLInteractionService {
|
|||||||
.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
|
.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<XMLRootDocument>? _ProbeFile(XDocument document, FileModel file) {
|
private List<XMLRootDocument>? _ProbeFile(XDocument document, FileModel file, Dictionary<string, IXMLRoot>? rootDefs) {
|
||||||
if (document.Root!.Name != "opus") {
|
if (document.Root!.Name != "opus") {
|
||||||
file.Log("Ein gültiges Dokument muss mit <opus> beginnen.");
|
file.Log("Ein gültiges Dokument muss mit <opus> beginnen.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<XMLRootDocument>? res = null;
|
List<XMLRootDocument>? res = null;
|
||||||
if (document.Root != null && _RootDefs != null) {
|
if (document.Root != null && rootDefs != null) {
|
||||||
foreach (var (_, root) in _RootDefs) {
|
foreach (var (_, root) in rootDefs) {
|
||||||
var elements = root.IsTypeOf(document.Root);
|
var elements = root.IsTypeOf(document.Root);
|
||||||
if (elements != null && elements.Any())
|
if (elements != null && elements.Any())
|
||||||
foreach (var elem in elements) {
|
foreach (var elem in elements) {
|
||||||
@@ -337,5 +336,8 @@ public class XMLInteractionService : IXMLInteractionService {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void OnSyntaxCheck(Dictionary<string, SyntaxCheckModel>? state) {
|
||||||
|
EventHandler<Dictionary<string, SyntaxCheckModel>?> eh = SyntaxCheck;
|
||||||
|
eh?.Invoke(this, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,16 +8,19 @@
|
|||||||
"FeatureManagement": {
|
"FeatureManagement": {
|
||||||
"AdminService": true,
|
"AdminService": true,
|
||||||
"LocalPublishService": true,
|
"LocalPublishService": true,
|
||||||
"SyntaxCheck": true
|
"SyntaxCheck": true,
|
||||||
|
"Notifications": true
|
||||||
},
|
},
|
||||||
|
"AllowedWebSocketConnections": "*",
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"HamannFileStoreLinux": "/home/simon/Downloads/test/",
|
"HamannFileStoreLinux": "/var/www/vhosts/test.hamann-ausgabe.de/httpdocs/Hamann/",
|
||||||
"HamannFileStoreWindows": "C:/Users/simon/Downloads/test/",
|
"HamannFileStoreWindows": "C:/Users/simon/Downloads/test/",
|
||||||
"BareRepositoryPathLinux": "/home/simon/Downloads/test/",
|
"BareRepositoryPathLinux": "/var/www/vhosts/test.hamann-ausgabe.de/httpdocs/Bare/",
|
||||||
"BareRepositoryPathWindows": "C:/Users/simon/source/hamann-xml/.git/",
|
"BareRepositoryPathWindows": "C:/Users/simon/source/hamann-xml/.git/",
|
||||||
"WorkingTreePathLinux": "/home/simon/Downloads/test/",
|
"WorkingTreePathLinux": "/var/www/vhosts/test.hamann-ausgabe.de/httpdocs/Repo/",
|
||||||
"WorkingTreePathWindows": "C:/Users/simon/source/hamann-xml/",
|
"WorkingTreePathWindows": "C:/Users/simon/source/hamann-xml/",
|
||||||
"RepositoryBranch": "main",
|
"RepositoryBranch": "testdata",
|
||||||
|
"RepositoryURL": "https://github.com/Theodor-Springmann-Stiftung/hamann-xml",
|
||||||
"StoredPDFPathWindows": "",
|
"StoredPDFPathWindows": "",
|
||||||
"StoredPDFPathLinux": "",
|
"StoredPDFPathLinux": "",
|
||||||
"FileSizeLimit": 52428800,
|
"FileSizeLimit": 52428800,
|
||||||
|
|||||||
@@ -1,357 +0,0 @@
|
|||||||
opus
|
|
||||||
opus/data
|
|
||||||
opus/data/definitions
|
|
||||||
opus/data/definitions/handDefs
|
|
||||||
opus/data/definitions/locationDefs
|
|
||||||
opus/data/definitions/personDefs
|
|
||||||
opus/data/definitions/structureDefs
|
|
||||||
opus/data/descriptions
|
|
||||||
opus/document
|
|
||||||
opus/document/letterText/added/anchor
|
|
||||||
opus/document/letterText/added/anchor/@ref
|
|
||||||
opus/document/letterText/address/aq/del/ul
|
|
||||||
opus/document/letterText/address/aq/line/@type
|
|
||||||
opus/document/letterText/address/aq/ul/aq
|
|
||||||
opus/document/letterText/address/aq/ul/line
|
|
||||||
opus/document/letterText/address/aq/ul/line/@autopsic
|
|
||||||
opus/document/letterText/address/aq/ul/line/@index
|
|
||||||
opus/document/letterText/address/del/aq/line
|
|
||||||
opus/document/letterText/address/del/aq/line/@autopsic
|
|
||||||
opus/document/letterText/address/del/aq/line/@index
|
|
||||||
opus/document/letterText/address/del/ul
|
|
||||||
opus/document/letterText/address/edit/aq/dul
|
|
||||||
opus/document/letterText/address/edit/aq/hand
|
|
||||||
opus/document/letterText/address/edit/aq/hand/@ref
|
|
||||||
opus/document/letterText/address/edit/aq/ul/super
|
|
||||||
opus/document/letterText/address/edit/hand
|
|
||||||
opus/document/letterText/address/edit/hand/aq
|
|
||||||
opus/document/letterText/address/edit/hand/aq/super
|
|
||||||
opus/document/letterText/address/edit/hand/@ref
|
|
||||||
opus/document/letterText/address/hand/aq
|
|
||||||
opus/document/letterText/address/hand/aq/ul
|
|
||||||
opus/document/letterText/address/hand/super/ul
|
|
||||||
opus/document/letterText/address/line/@type
|
|
||||||
opus/document/letterText/address/note
|
|
||||||
opus/document/letterText/address/nr
|
|
||||||
opus/document/letterText/address/page
|
|
||||||
opus/document/letterText/address/page/@autopsic
|
|
||||||
opus/document/letterText/address/page/@index
|
|
||||||
opus/document/letterText/align/address/aq
|
|
||||||
opus/document/letterText/align/aq/del
|
|
||||||
opus/document/letterText/align/aq/edit
|
|
||||||
opus/document/letterText/align/aq/edit/@ref
|
|
||||||
opus/document/letterText/align/aq/super
|
|
||||||
opus/document/letterText/align/datum/del/aq
|
|
||||||
opus/document/letterText/align/datum/edit/gr
|
|
||||||
opus/document/letterText/align/datum/nr
|
|
||||||
opus/document/letterText/align/datum/sub/aq
|
|
||||||
opus/document/letterText/align/del/gr
|
|
||||||
opus/document/letterText/align/edit/aq/super
|
|
||||||
opus/document/letterText/align/edit/datum/del
|
|
||||||
opus/document/letterText/align/edit/datum/del/nr
|
|
||||||
opus/document/letterText/align/edit/datum/super
|
|
||||||
opus/document/letterText/align/edit/gr
|
|
||||||
opus/document/letterText/align/edit/gr/del
|
|
||||||
opus/document/letterText/align/edit/sig/aq
|
|
||||||
opus/document/letterText/align/edit/super
|
|
||||||
opus/document/letterText/align/hand/datum/super
|
|
||||||
opus/document/letterText/align/hand/datum/ul
|
|
||||||
opus/document/letterText/align/hand/del
|
|
||||||
opus/document/letterText/align/hand/sig
|
|
||||||
opus/document/letterText/align/hand/sig/aq
|
|
||||||
opus/document/letterText/align/sig/datum
|
|
||||||
opus/document/letterText/align/sig/nr/aq
|
|
||||||
opus/document/letterText/align/up/aq
|
|
||||||
opus/document/letterText/anchor/added
|
|
||||||
opus/document/letterText/anchor/note
|
|
||||||
opus/document/letterText/aq/address/del
|
|
||||||
opus/document/letterText/aq/address/edit
|
|
||||||
opus/document/letterText/aq/address/edit/@ref
|
|
||||||
opus/document/letterText/aq/address/edit/ul
|
|
||||||
opus/document/letterText/aq/align/ul
|
|
||||||
opus/document/letterText/aq/del/edit
|
|
||||||
opus/document/letterText/aq/del/edit/@ref
|
|
||||||
opus/document/letterText/aq/dul/line
|
|
||||||
opus/document/letterText/aq/dul/line/@autopsic
|
|
||||||
opus/document/letterText/aq/dul/line/@index
|
|
||||||
opus/document/letterText/aq/edit/del
|
|
||||||
opus/document/letterText/aq/edit/del/nr
|
|
||||||
opus/document/letterText/aq/super/ul
|
|
||||||
opus/document/letterText/aq/ul/added
|
|
||||||
opus/document/letterText/aq/ul/del
|
|
||||||
opus/document/letterText/aq/ul/super
|
|
||||||
opus/document/letterText/datum/align/added
|
|
||||||
opus/document/letterText/datum/align/datum
|
|
||||||
opus/document/letterText/datum/align/del
|
|
||||||
opus/document/letterText/datum/aq/line
|
|
||||||
opus/document/letterText/datum/aq/line/@autopsic
|
|
||||||
opus/document/letterText/datum/aq/line/@index
|
|
||||||
opus/document/letterText/datum/edit/super
|
|
||||||
opus/document/letterText/datum/edit/ul
|
|
||||||
opus/document/letterText/datum/gr
|
|
||||||
opus/document/letterText/datum/hand
|
|
||||||
opus/document/letterText/datum/hand/@ref
|
|
||||||
opus/document/letterText/datum/super/aq
|
|
||||||
opus/document/letterText/del/added
|
|
||||||
opus/document/letterText/del/aq/del
|
|
||||||
opus/document/letterText/del/del/nr
|
|
||||||
opus/document/letterText/del/edit/nr
|
|
||||||
opus/document/letterText/del/gr
|
|
||||||
opus/document/letterText/del/gr/edit
|
|
||||||
opus/document/letterText/del/gr/edit/@ref
|
|
||||||
opus/document/letterText/del/gr/line
|
|
||||||
opus/document/letterText/del/gr/line/@autopsic
|
|
||||||
opus/document/letterText/del/gr/line/@index
|
|
||||||
opus/document/letterText/del/super
|
|
||||||
opus/document/letterText/del/super/aq
|
|
||||||
opus/document/letterText/del/ul/line
|
|
||||||
opus/document/letterText/del/ul/line/@autopsic
|
|
||||||
opus/document/letterText/del/ul/line/@index
|
|
||||||
opus/document/letterText/dul/super
|
|
||||||
opus/document/letterText/edit/added/nr
|
|
||||||
opus/document/letterText/edit/added/ul
|
|
||||||
opus/document/letterText/edit/address/hand
|
|
||||||
opus/document/letterText/edit/address/hand/@ref
|
|
||||||
opus/document/letterText/edit/address/hand/ul
|
|
||||||
opus/document/letterText/edit/address/line
|
|
||||||
opus/document/letterText/edit/address/line/@autopsic
|
|
||||||
opus/document/letterText/edit/address/line/@index
|
|
||||||
opus/document/letterText/edit/address/ul/aq
|
|
||||||
opus/document/letterText/edit/align/aq/ul
|
|
||||||
opus/document/letterText/edit/align/datum/aq
|
|
||||||
opus/document/letterText/edit/align/edit
|
|
||||||
opus/document/letterText/edit/align/edit/aq
|
|
||||||
opus/document/letterText/edit/align/edit/@ref
|
|
||||||
opus/document/letterText/edit/anchor
|
|
||||||
opus/document/letterText/edit/anchor/@ref
|
|
||||||
opus/document/letterText/edit/aq/dul
|
|
||||||
opus/document/letterText/edit/aq/edit
|
|
||||||
opus/document/letterText/edit/aq/edit/@ref
|
|
||||||
opus/document/letterText/edit/aq/line/@tab
|
|
||||||
opus/document/letterText/edit/aq/ul/del
|
|
||||||
opus/document/letterText/edit/aq/ul/line
|
|
||||||
opus/document/letterText/edit/aq/ul/line/@autopsic
|
|
||||||
opus/document/letterText/edit/aq/ul/line/@index
|
|
||||||
opus/document/letterText/edit/del/aq/del
|
|
||||||
opus/document/letterText/edit/del/del/line
|
|
||||||
opus/document/letterText/edit/del/del/line/@autopsic
|
|
||||||
opus/document/letterText/edit/del/del/line/@index
|
|
||||||
opus/document/letterText/edit/del/page
|
|
||||||
opus/document/letterText/edit/del/page/@autopsic
|
|
||||||
opus/document/letterText/edit/del/page/@index
|
|
||||||
opus/document/letterText/edit/edit/aq/del
|
|
||||||
opus/document/letterText/edit/edit/del/aq
|
|
||||||
opus/document/letterText/edit/edit/edit/aq
|
|
||||||
opus/document/letterText/edit/edit/page
|
|
||||||
opus/document/letterText/edit/edit/page/@autopsic
|
|
||||||
opus/document/letterText/edit/edit/page/@index
|
|
||||||
opus/document/letterText/edit/edit/super
|
|
||||||
opus/document/letterText/edit/gr/del/nr
|
|
||||||
opus/document/letterText/edit/hand/align/aq
|
|
||||||
opus/document/letterText/edit/hand/aq/del
|
|
||||||
opus/document/letterText/edit/hand/aq/del/ul
|
|
||||||
opus/document/letterText/edit/hand/aq/nr
|
|
||||||
opus/document/letterText/edit/hand/del/aq
|
|
||||||
opus/document/letterText/edit/hand/super
|
|
||||||
opus/document/letterText/edit/hand/ul
|
|
||||||
opus/document/letterText/edit/nr/aq/del
|
|
||||||
opus/document/letterText/edit/sig/aq
|
|
||||||
opus/document/letterText/edit/sig/aq/ul
|
|
||||||
opus/document/letterText/edit/sig/line
|
|
||||||
opus/document/letterText/edit/sig/line/@autopsic
|
|
||||||
opus/document/letterText/edit/sig/line/@index
|
|
||||||
opus/document/letterText/edit/ul/del/nr
|
|
||||||
opus/document/letterText/edit/ul/edit
|
|
||||||
opus/document/letterText/edit/ul/edit/@ref
|
|
||||||
opus/document/letterText/edit/ul/nr
|
|
||||||
opus/document/letterText/edit/ul/ul
|
|
||||||
opus/document/letterText/fn/added/aq
|
|
||||||
opus/document/letterText/fn/del
|
|
||||||
opus/document/letterText/fn/hand/aq
|
|
||||||
opus/document/letterText/fn/line/@type
|
|
||||||
opus/document/letterText/fn/note/ul
|
|
||||||
opus/document/letterText/ful/aq
|
|
||||||
opus/document/letterText/gr/del
|
|
||||||
opus/document/letterText/gr/edit/del
|
|
||||||
opus/document/letterText/gr/line/@tab
|
|
||||||
opus/document/letterText/hand/address/aq/del
|
|
||||||
opus/document/letterText/hand/address/aq/del/nr
|
|
||||||
opus/document/letterText/hand/address/aq/del/nr/ul
|
|
||||||
opus/document/letterText/hand/address/aq/line
|
|
||||||
opus/document/letterText/hand/address/aq/line/@autopsic
|
|
||||||
opus/document/letterText/hand/address/aq/line/@index
|
|
||||||
opus/document/letterText/hand/address/aq/line/@tab
|
|
||||||
opus/document/letterText/hand/address/edit
|
|
||||||
opus/document/letterText/hand/address/edit/@ref
|
|
||||||
opus/document/letterText/hand/address/edit/ul
|
|
||||||
opus/document/letterText/hand/address/edit/ul/aq
|
|
||||||
opus/document/letterText/hand/align/datum/edit
|
|
||||||
opus/document/letterText/hand/align/datum/edit/@ref
|
|
||||||
opus/document/letterText/hand/align/datum/edit/super
|
|
||||||
opus/document/letterText/hand/aq/address
|
|
||||||
opus/document/letterText/hand/aq/address/line
|
|
||||||
opus/document/letterText/hand/aq/address/line/@autopsic
|
|
||||||
opus/document/letterText/hand/aq/address/line/@index
|
|
||||||
opus/document/letterText/hand/aq/address/ul
|
|
||||||
opus/document/letterText/hand/datum/align
|
|
||||||
opus/document/letterText/hand/datum/align/@pos
|
|
||||||
opus/document/letterText/hand/datum/edit
|
|
||||||
opus/document/letterText/hand/datum/edit/aq
|
|
||||||
opus/document/letterText/hand/datum/edit/@ref
|
|
||||||
opus/document/letterText/hand/del/aq
|
|
||||||
opus/document/letterText/hand/del/line
|
|
||||||
opus/document/letterText/hand/del/line/@autopsic
|
|
||||||
opus/document/letterText/hand/del/line/@index
|
|
||||||
opus/document/letterText/hand/del/line/@tab
|
|
||||||
opus/document/letterText/hand/del/nr
|
|
||||||
opus/document/letterText/hand/edit/added
|
|
||||||
opus/document/letterText/hand/edit/aq/ul
|
|
||||||
opus/document/letterText/hand/edit/del/nr
|
|
||||||
opus/document/letterText/hand/edit/line
|
|
||||||
opus/document/letterText/hand/edit/line/@autopsic
|
|
||||||
opus/document/letterText/hand/edit/line/@index
|
|
||||||
opus/document/letterText/hand/edit/nr
|
|
||||||
opus/document/letterText/hand/edit/ul/aq
|
|
||||||
opus/document/letterText/hand/gr/del
|
|
||||||
opus/document/letterText/hand/gr/line
|
|
||||||
opus/document/letterText/hand/gr/line/@autopsic
|
|
||||||
opus/document/letterText/hand/gr/line/@index
|
|
||||||
opus/document/letterText/hand/ps
|
|
||||||
opus/document/letterText/hand/ps/aq
|
|
||||||
opus/document/letterText/hand/ps/datum
|
|
||||||
opus/document/letterText/hand/ps/datum/aq
|
|
||||||
opus/document/letterText/hand/ul/aq
|
|
||||||
opus/document/letterText/hand/ul/nr
|
|
||||||
opus/document/letterText/note/aq/ul
|
|
||||||
opus/document/letterText/note/line/@tab
|
|
||||||
opus/document/letterText/note/ul
|
|
||||||
opus/document/letterText/nr/del
|
|
||||||
opus/document/letterText/ps/added
|
|
||||||
opus/document/letterText/ps/align
|
|
||||||
opus/document/letterText/ps/align/aq
|
|
||||||
opus/document/letterText/ps/align/@pos
|
|
||||||
opus/document/letterText/ps/aq/line
|
|
||||||
opus/document/letterText/ps/aq/line/@autopsic
|
|
||||||
opus/document/letterText/ps/aq/line/@index
|
|
||||||
opus/document/letterText/ps/aq/super
|
|
||||||
opus/document/letterText/ps/del/line
|
|
||||||
opus/document/letterText/ps/del/line/@autopsic
|
|
||||||
opus/document/letterText/ps/del/line/@index
|
|
||||||
opus/document/letterText/ps/edit/dul
|
|
||||||
opus/document/letterText/ps/edit/dul/aq
|
|
||||||
opus/document/letterText/ps/ps
|
|
||||||
opus/document/letterText/ps/ps/del
|
|
||||||
opus/document/letterText/ps/ul/aq
|
|
||||||
opus/document/letterText/sig/align/ul
|
|
||||||
opus/document/letterText/sig/datum
|
|
||||||
opus/document/letterText/super/del
|
|
||||||
opus/document/letterText/tab/ful
|
|
||||||
opus/document/letterText/tabs/align/aq
|
|
||||||
opus/document/letterText/tabs/align/edit
|
|
||||||
opus/document/letterText/tabs/align/edit/aq
|
|
||||||
opus/document/letterText/tabs/align/edit/@ref
|
|
||||||
opus/document/letterText/tabs/aq/ul
|
|
||||||
opus/document/letterText/tabs/edit
|
|
||||||
opus/document/letterText/tabs/edit/page
|
|
||||||
opus/document/letterText/tabs/edit/page/@autopsic
|
|
||||||
opus/document/letterText/tabs/edit/page/@index
|
|
||||||
opus/document/letterText/tabs/edit/@ref
|
|
||||||
opus/document/letterText/tabs/edit/tab/del
|
|
||||||
opus/document/letterText/tabs/edit/tab/dul
|
|
||||||
opus/document/letterText/tabs/edit/tab/edit/tul
|
|
||||||
opus/document/letterText/tabs/edit/tab/ul
|
|
||||||
opus/document/letterText/tabs/line/@type
|
|
||||||
opus/document/letterText/tabs/tab/aq/added
|
|
||||||
opus/document/letterText/tabs/tab/aq/super
|
|
||||||
opus/document/letterText/tabs/tab/aq/ul
|
|
||||||
opus/document/letterText/tabs/tab/datum/aq
|
|
||||||
opus/document/letterText/tabs/tab/edit/aq
|
|
||||||
opus/document/letterText/tabs/tab/ful/aq
|
|
||||||
opus/document/letterText/tabs/tab/ful/del
|
|
||||||
opus/document/letterText/tabs/tab/ful/del/nr
|
|
||||||
opus/document/letterText/tabs/tab/nr
|
|
||||||
opus/document/letterText/tabs/tab/nr/aq
|
|
||||||
opus/document/letterText/tabs/tab/tab
|
|
||||||
opus/document/letterText/tabs/tab/tab/@value
|
|
||||||
opus/document/letterText/tabs/tab/up/edit
|
|
||||||
opus/document/letterText/tabs/tab/up/edit/aq
|
|
||||||
opus/document/letterText/tabs/tab/up/edit/@ref
|
|
||||||
opus/document/letterText/tab/ul
|
|
||||||
opus/document/letterText/ul/aq/added
|
|
||||||
opus/document/letterText/ul/edit/added
|
|
||||||
opus/document/letterText/ul/edit/del
|
|
||||||
opus/document/letterText/ul/edit/ul
|
|
||||||
opus/document/letterText/ul/super
|
|
||||||
opus/document/letterText/up
|
|
||||||
opus/edits
|
|
||||||
opus/edits/editreason/aq/del
|
|
||||||
opus/edits/editreason/aq/nr
|
|
||||||
opus/edits/editreason/aq/ul
|
|
||||||
opus/edits/editreason/del/added
|
|
||||||
opus/edits/editreason/nr
|
|
||||||
opus/edits/editreason/zh/added/aq
|
|
||||||
opus/edits/editreason/zh/address/hand
|
|
||||||
opus/edits/editreason/zh/address/hand/@ref
|
|
||||||
opus/edits/editreason/zh/address/ul
|
|
||||||
opus/edits/editreason/zh/aq/del
|
|
||||||
opus/edits/editreason/zh/aq/dul
|
|
||||||
opus/edits/editreason/zh/aq/nr
|
|
||||||
opus/edits/editreason/zh/del/note
|
|
||||||
opus/edits/editreason/zh/dul/aq
|
|
||||||
opus/edits/editreason/zh/note
|
|
||||||
opus/edits/editreason/zh/sig/ul
|
|
||||||
opus/edits/editreason/zh/ul/added
|
|
||||||
opus/edits/editreason/zh/ul/del
|
|
||||||
opus/kommentare
|
|
||||||
opus/kommentare/kommcat/kommentar/eintrag/titel/link
|
|
||||||
opus/kommentare/kommcat/kommentar/eintrag/titel/link/@linktext
|
|
||||||
opus/kommentare/kommcat/kommentar/eintrag/titel/link/@ref
|
|
||||||
opus/kommentare/kommcat/kommentar/lemma/titel
|
|
||||||
opus/kommentare/kommcat/kommentar/lemma/wwwlink
|
|
||||||
opus/kommentare/kommcat/kommentar/lemma/wwwlink/@address
|
|
||||||
opus/kommentare/kommcat/kommentar/subsection/wwwlink
|
|
||||||
opus/kommentare/kommcat/kommentar/subsection/wwwlink/@address
|
|
||||||
opus/marginalien
|
|
||||||
opus/marginalien/marginal/eintrag
|
|
||||||
opus/traditions
|
|
||||||
opus/traditions/letterTradition/align/note
|
|
||||||
opus/traditions/letterTradition/del
|
|
||||||
opus/traditions/letterTradition/del/aq
|
|
||||||
opus/traditions/letterTradition/note/ul
|
|
||||||
opus/traditions/letterTradition/nr
|
|
||||||
opus/traditions/letterTradition/ZHText/align/aq/del
|
|
||||||
opus/traditions/letterTradition/ZHText/align/aq/ul
|
|
||||||
opus/traditions/letterTradition/ZHText/align/datum
|
|
||||||
opus/traditions/letterTradition/ZHText/align/del/aq
|
|
||||||
opus/traditions/letterTradition/ZHText/aq/line/@type
|
|
||||||
opus/traditions/letterTradition/ZHText/aq/nr
|
|
||||||
opus/traditions/letterTradition/ZHText/aq/ul/line
|
|
||||||
opus/traditions/letterTradition/ZHText/aq/ul/line/@autopsic
|
|
||||||
opus/traditions/letterTradition/ZHText/aq/ul/line/@index
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/align/aq
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/aq/line
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/aq/line/@autopsic
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/aq/line/@index
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/dul
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/edit/ul
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/nr
|
|
||||||
opus/traditions/letterTradition/ZHText/edit/super
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/align/super
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/aq/line
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/aq/line/@autopsic
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/aq/line/@index
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/aq/ul
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/edit/aq
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/edit/dul
|
|
||||||
opus/traditions/letterTradition/ZHText/hand/ul/aq
|
|
||||||
opus/traditions/letterTradition/ZHText/hb
|
|
||||||
opus/traditions/letterTradition/ZHText/note/align
|
|
||||||
opus/traditions/letterTradition/ZHText/note/align/@pos
|
|
||||||
opus/traditions/letterTradition/ZHText/nr/aq
|
|
||||||
opus/traditions/letterTradition/ZHText/tabs
|
|
||||||
opus/traditions/letterTradition/ZHText/tabs/tab/aq
|
|
||||||
opus/traditions/letterTradition/ZHText/tabs/tab/del
|
|
||||||
opus/traditions/letterTradition/ZHText/tabs/tab/ful
|
|
||||||
opus/traditions/letterTradition/ZHText/tabs/tab/ful/del
|
|
||||||
opus/traditions/letterTradition/ZHText/tabs/tab/ful/del/nr
|
|
||||||
opus/traditions/letterTradition/ZHText/ul/super/aq
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -227,7 +227,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ha-index .ha-indexbody .ha-filterlist .ha-personfilter .ha-personlist {
|
.ha-index .ha-indexbody .ha-filterlist .ha-personfilter .ha-personlist {
|
||||||
@apply max-h-[23rem] overflow-y-auto overflow-x-hidden py-1 pl-1 mr-2
|
@apply max-h-[23rem] overflow-y-auto overflow-x-hidden py-1 pl-1 mr-2 transition-all
|
||||||
}
|
}
|
||||||
|
|
||||||
.ha-index .ha-indexbody .ha-filterlist .ha-personfilter .ha-personlist a {
|
.ha-index .ha-indexbody .ha-filterlist .ha-personfilter .ha-personlist a {
|
||||||
@@ -235,6 +235,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ha-index .ha-indexbody .ha-filterlist .ha-personfilter .ha-personlist a:nth-child(odd) {
|
.ha-index .ha-indexbody .ha-filterlist .ha-personfilter .ha-personlist a:nth-child(odd) {
|
||||||
@apply block
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
84
HaWeb/wwwroot/css/notifications.css
Normal file
84
HaWeb/wwwroot/css/notifications.css
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
@layer components {
|
||||||
|
.ha-notifications {
|
||||||
|
@apply fixed right-5 bottom-4 px-3 min-w-full
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications a {
|
||||||
|
@apply underline decoration-dotted hover:decoration-solid
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ha-notifications .ha-notcontent {
|
||||||
|
@apply absolute bottom-0 right-0 flex flex-row
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.loading .ha-noticon {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.green {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.green .ha-noticon {
|
||||||
|
@apply text-emerald-700
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.orange {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.orange .ha-noticon {
|
||||||
|
@apply text-yellow-500
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.red {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.red .ha-noticon {
|
||||||
|
@apply text-rose-600
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-noticon {
|
||||||
|
@apply w-5 inline-block pt-1 relative top-[2px] text-slate-400 transition-all duration-500
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-noticon svg {
|
||||||
|
@apply shadow-red-800 drop-shadow-md
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-commslog {
|
||||||
|
@apply shadow-md inline-block bg-slate-50 mr-2 px-2 py-0.5 opacity-0 transition-all duration-300 text-sm font-mono
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications:hover .ha-commslog {
|
||||||
|
@apply !opacity-100
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications:hover .ha-noticon svg {
|
||||||
|
@apply !opacity-100 drop-shadow-xl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.visible .ha-commslog {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.loading .ha-noticon {
|
||||||
|
animation: ha-pulse 1.1s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ha-pulse {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: .6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-notifications.imp .ha-commslog {
|
||||||
|
animation: ha-pulse 5s cubic-bezier(0.4, 0, 0.6, 1);
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
/* STYLES */
|
/* STYLES */
|
||||||
.ha-scrollbutton {
|
.ha-scrollbutton {
|
||||||
@apply opacity-0 transition-opacity duration-500 cursor-pointer fixed right-0 bottom-6 text-center py-2 pr-6 bg-slate-50 dark:bg-slate-700 dark:text-white px-2 shadow rounded-l-xl transition-all hover:shadow-md text-hamannSlate-700 hover:text-hamannSlate-500
|
@apply opacity-0 transition-opacity duration-500 cursor-pointer fixed right-0 bottom-48 text-center py-2 pr-6 bg-slate-50 dark:bg-slate-700 dark:text-white px-2 shadow rounded-l-xl transition-all hover:shadow-md text-hamannSlate-700 hover:text-hamannSlate-500
|
||||||
}
|
}
|
||||||
|
|
||||||
.ha-scrollbuttonarrow {
|
.ha-scrollbuttonarrow {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ha-location {
|
.ha-location {
|
||||||
@apply !text-hamannHighlight absolute text-xl hidden sm:inline-block
|
@apply !text-hamannSlate-300 absolute text-xl hidden sm:inline-block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@
|
|||||||
@import "./register.css";
|
@import "./register.css";
|
||||||
@import "./letterhead.css";
|
@import "./letterhead.css";
|
||||||
@import "./letter.css";
|
@import "./letter.css";
|
||||||
@import "./upload.css";
|
@import "./xmlstate.css";
|
||||||
@import "./index.css";
|
@import "./index.css";
|
||||||
@import "./search.css";
|
@import "./search.css";
|
||||||
|
@import "./notifications.css";
|
||||||
@import "./print.css";
|
@import "./print.css";
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
@layer components {
|
|
||||||
/* COLORS */
|
|
||||||
|
|
||||||
|
|
||||||
/* STYLES */
|
|
||||||
.ha-adminuploadfields {
|
|
||||||
@apply flex flex-row flex-wrap gap-x-4 gap-y-4
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadfield {
|
|
||||||
@apply block shrink-0 grow bg-slate-50 rounded shadow basis-64 max-w-xs
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadfield:hover {
|
|
||||||
@apply brightness-110
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadfield.active {
|
|
||||||
@apply !text-black brightness-110 shadow-inner
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadfield .ha-uploadfieldname {
|
|
||||||
@apply px-3 pt-2 pb-1
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadusedfiles {
|
|
||||||
@apply text-sm whitespace-nowrap overflow-hidden text-ellipsis w-auto bg-slate-200 border-t border-slate-300 bg-opacity-30 px-2 py-0.5
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadusedfiles.ha-uploadusedfilesnotfound {
|
|
||||||
@apply bg-slate-500 border-slate-500
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadpublishforms {
|
|
||||||
@apply flex flex-row gap-x-4 grow
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadform {
|
|
||||||
@apply bg-slate-50 rounded shadow grow relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadform .ha-uploadtext {
|
|
||||||
@apply text-center
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadform .ha-lds-ellipsis {
|
|
||||||
@apply left-1/2 -ml-[20px]
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadform .ha-uploadfilelabel {
|
|
||||||
@apply inline-block px-4 py-1 pt-2 cursor-pointer w-full h-full hover:bg-slate-100
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-uploadform .ha-uploadmessage {
|
|
||||||
@apply text-sm bg-slate-700 bg-opacity-30 px-1 rounded-sm
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-publishbutton {
|
|
||||||
@apply inline-block px-2 py-1 pt-2 cursor-pointer w-full h-full bg-slate-50 shadow shrink hover:bg-slate-100
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-publishbutton .ha-publishtext {
|
|
||||||
@apply text-center
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-adminuploadfields .ha-publishbutton .ha-publishmessage {
|
|
||||||
@apply text-sm bg-slate-700 bg-opacity-30 px-1 rounded-sm
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadheader {
|
|
||||||
@apply bg-slate-50 w-full mt-4 px-16 pt-12 pb-8 flex flex-row
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadheader h1 {
|
|
||||||
@apply text-5xl
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer {
|
|
||||||
@apply w-full bg-slate-50 flex flex-col gap-y-2
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-publishfilelist {
|
|
||||||
@apply px-16 mb-8
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-publishfilelist .ha-publishfilelisttitle {
|
|
||||||
@apply text-xl mb-2
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-publishfilelist td {
|
|
||||||
@apply align-text-top pr-6
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-publishfilelist .ha-publishfilelabel {
|
|
||||||
@apply relative mt-4 ml-6 rounded-md px-3 border-2 border-blue-600 hover:border-2 hover:shadow active:shadow-inner hover:border-blue-800 cursor-pointer float-right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-availablefiles {
|
|
||||||
@apply px-16 border border-slate-200 hover:border-slate-800 py-2 cursor-pointer select-none
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-availablefiles .ha-availablefilestitle {
|
|
||||||
@apply text-2xl
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-availablefiles .ha-usedfilelist {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-filesheader {
|
|
||||||
@apply mb-4
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-availablefileslist {
|
|
||||||
@apply px-16 pt-4
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-errorswarnings {
|
|
||||||
@apply flex flex-row gap-x-2
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-errorswarnings .ha-criticalerrors,
|
|
||||||
.ha-uploadcontainer .ha-errorswarnings .ha-warnings {
|
|
||||||
@apply basis-1/2 min-w-[40%] min-h-[400px] overflow-x-hidden overflow-y-scroll grow shrink
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-errorswarnings .ha-criticalerrors {
|
|
||||||
@apply bg-red-200
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-errorswarnings .ha-warnings {
|
|
||||||
@apply bg-orange-200
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-crossfilechecking {
|
|
||||||
@apply w-full bg-cyan-200 grow shrink-0 h-full min-h-[400px]
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-hamannfilechooser {
|
|
||||||
@apply px-16 pb-16
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-setendyearform {
|
|
||||||
@apply px-16 pb-16 float-right
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-uploadcontainer .ha-setendyearform .ha-setendyearbutton {
|
|
||||||
@apply mt-4 ml-6 rounded-md px-3 border-2 border-blue-600 hover:border-2 hover:shadow active:shadow-inner hover:border-blue-800 cursor-pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Classes for FileList Component */
|
|
||||||
.ha-filelistfieldset {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-filelistfieldset .ha-filelistlegend {
|
|
||||||
@apply mb-2 text-xl
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile {
|
|
||||||
@apply flex flex-row gap-x-4 px-1 items-center
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile:nth-child(even) {
|
|
||||||
@apply bg-slate-100
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistlist {
|
|
||||||
@apply h-96 overflow-x-hidden overflow-y-scroll pr-4
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile .ha-filelistname {
|
|
||||||
@apply font-mono
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction {
|
|
||||||
@apply text-sm
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction .ha-filelistproduction {
|
|
||||||
@apply inline-block border rounded-md text-teal-600 border-teal-600 px-2 mr-2
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction .ha-filelistused {
|
|
||||||
@apply inline-block border rounded-md text-indigo-600 border-indigo-600 px-2
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistfile .ha-filelistmodified {
|
|
||||||
@apply grow text-right
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistoutput {
|
|
||||||
@apply mt-4 ml-6
|
|
||||||
}
|
|
||||||
|
|
||||||
.ha-selectfilesform .ha-filelistbutton {
|
|
||||||
@apply mt-4 ml-6 rounded-md px-3 border-2 border-blue-600 hover:border-2 hover:shadow active:shadow-inner hover:border-blue-800 cursor-pointer float-right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
180
HaWeb/wwwroot/css/xmlstate.css
Normal file
180
HaWeb/wwwroot/css/xmlstate.css
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
@layer components {
|
||||||
|
.ha-xmlstateheader {
|
||||||
|
@apply bg-slate-50 w-full mt-4 px-16 pt-12 pb-8 flex flex-row
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-xmlstateheader h1 {
|
||||||
|
@apply text-5xl
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfiles {
|
||||||
|
@apply mt-4 border border-slate-300 px-4 py-3
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-repo {
|
||||||
|
@apply relative
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-repodata {
|
||||||
|
@apply bg-slate-50 px-3.5 py-1 w-max shadow
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-repodata div {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-repodata a {
|
||||||
|
@apply underline decoration-dotted
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-repofilecount {
|
||||||
|
@apply absolute right-0 bottom-0 bg-slate-50 px-3 py-1 shadow
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileslist {
|
||||||
|
@apply flex flex-col gap-3 mt-3
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader {
|
||||||
|
@apply flex flex-row gap-2 bg-slate-50 pl-3.5 pr-2.5 rounded-md py-1 w-full shadow-md select-none border-b
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.expandable {
|
||||||
|
@apply cursor-pointer rounded-none !rounded-t-md border-b
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.orange {
|
||||||
|
@apply border-b border-orange-300 bg-orange-50
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.orange .ha-filestatusicon svg {
|
||||||
|
@apply text-orange-700 !pt-0
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.red {
|
||||||
|
@apply border-b border-red-400 bg-red-50
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.red .ha-filestatusicon svg {
|
||||||
|
@apply text-red-700 !pt-[0rem]
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.green {
|
||||||
|
@apply bg-teal-50
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.green .ha-filestatusicon svg {
|
||||||
|
@apply text-green-700
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileheader.expandable.red+.ha-managedfileannotations {
|
||||||
|
@apply bg-red-100
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileannotations {
|
||||||
|
@apply hidden font-mono w-full text-base px-4 pt-1.5 pb-1 rounded-b-md shadow bg-orange-100 overflow-x-hidden overflow-y-auto max-h-72
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileannotations table {
|
||||||
|
@apply text-left w-full
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileannotations table td,
|
||||||
|
.ha-managedfileannotations table th {
|
||||||
|
@apply pr-4
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfileannotations table th {
|
||||||
|
@apply border-b border-black
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ha-managedfileheader.expandable.expanded+.ha-managedfileannotations {
|
||||||
|
@apply block
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-managedfile div:first-child {
|
||||||
|
@apply grow
|
||||||
|
}
|
||||||
|
.ha-managedfile .ha-filestatusicon {
|
||||||
|
@apply w-5 pt-[.14rem]
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-scbutton {
|
||||||
|
@apply mt-4 rounded-md px-4 py-1 border-2 bg-blue-600 shadow-blue-100 hover:shadow-blue-200 duration-500 text-slate-50 shadow-md hover:shadow-xl active:shadow-inner hover:border-blue-600 cursor-pointer absolute bottom-4 right-6 transition-all hover:ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-scbutton.loading {
|
||||||
|
@apply shadow-blue-100 saturate-[.8] shadow-xl transition-all ease-in-out border-blue-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Classes for FileList Component */
|
||||||
|
.ha-filelistfieldset {
|
||||||
|
@apply bg-slate-50 px-3 py-2 mt-4
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-filelistfieldset .ha-filelistlegend {
|
||||||
|
@apply pb-2 text-xl
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform {
|
||||||
|
@apply relative
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistfile {
|
||||||
|
@apply flex flex-row gap-x-4 px-1 items-center
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistfile:nth-child(even) {
|
||||||
|
@apply bg-slate-100
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistlist {
|
||||||
|
@apply h-96 overflow-x-hidden overflow-y-scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistfile .ha-filelistname {
|
||||||
|
@apply font-mono
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction {
|
||||||
|
@apply text-sm
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction .ha-filelistproduction {
|
||||||
|
@apply inline-block border rounded-md text-teal-600 border-teal-600 px-2 mr-2
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistfile .ha-filelistmodified {
|
||||||
|
@apply grow text-right
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistoutput {
|
||||||
|
@apply mt-4 ml-6
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistbutton {
|
||||||
|
@apply mt-4 rounded-md px-4 py-1 border-2 bg-blue-600 shadow-blue-100 hover:shadow-blue-200 duration-500 text-slate-50 shadow-md hover:shadow-xl active:shadow-inner hover:border-blue-600 cursor-pointer absolute bottom-4 right-6 transition-all hover:ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistbutton.loading {
|
||||||
|
@apply shadow-blue-100 saturate-[.8] shadow-xl transition-all ease-in-out border-blue-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-scbutton.loading {
|
||||||
|
animation: ha-pulse .7s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ha-selectfilesform .ha-filelistbutton.loading {
|
||||||
|
animation: ha-pulse .7s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ha-pulse {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: .6;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ function getCookie(name) {
|
|||||||
const USESubmit = async function (oFormElement, file = null) {
|
const USESubmit = async function (oFormElement, file = null) {
|
||||||
let fd = new FormData(oFormElement);
|
let fd = new FormData(oFormElement);
|
||||||
document.getElementById("ha-filelistbutton").style.pointerEvents = "none";
|
document.getElementById("ha-filelistbutton").style.pointerEvents = "none";
|
||||||
document.getElementById("ha-lds-ellipsis-load").style.display = "inline-block";
|
document.getElementById("ha-filelistbutton").classList.add("loading");
|
||||||
await fetch(oFormElement.action, {
|
await fetch(oFormElement.action, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -17,40 +17,97 @@ const USESubmit = async function (oFormElement, file = null) {
|
|||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(json => {
|
.then(json => {
|
||||||
|
document.getElementById("ha-filelistbutton").classList.remove("loading");
|
||||||
|
document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
|
||||||
if ("Error" in json) {
|
if ("Error" in json) {
|
||||||
document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
|
document.getElementById("ha-filelistoutput").textContent = json.Error;
|
||||||
document.getElementById("ha-lds-ellipsis-load").style.display = "none";
|
|
||||||
document.getElementById("ha-filelistoutput").textContent = json.Error;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
|
location.reload();
|
||||||
document.getElementById("ha-lds-ellipsis-load").style.display = "none";
|
|
||||||
location.reload();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch ((e) => {
|
.catch ((e) => {
|
||||||
|
document.getElementById("ha-filelistbutton").classList.remove("loading");
|
||||||
document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
|
document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
|
||||||
document.getElementById("ha-lds-ellipsis-load").style.display = "none";
|
|
||||||
document.getElementById("ha-filelistoutput").textContent = e;
|
document.getElementById("ha-filelistoutput").textContent = e;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const YEARSUBMIT = async function (oFormElement, file = null) {
|
const GETSyntaxCheck = async function (oFormElement, file = null) {
|
||||||
let fd = new FormData(oFormElement);
|
document.getElementById("ha-scbutton").style.pointerEvents = "none";
|
||||||
document.getElementById("ha-setendyearbutton").style.pointerEvents = "none";
|
document.getElementById("ha-scbutton").classList.toggle("loading");
|
||||||
await fetch(oFormElement.action, {
|
await fetch(oFormElement.action)
|
||||||
method: 'POST',
|
.then(response => response.json())
|
||||||
headers: {
|
.then(j => {
|
||||||
'RequestVerificationToken': getCookie('RequestVerificationToken')
|
Object.entries(j).forEach(([key, value]) => {
|
||||||
},
|
var e = document.getElementById(key);
|
||||||
body: fd
|
if (e !== null && !e.classList.contains("red")) {
|
||||||
})
|
var h = e.querySelector(".ha-managedfileheader");
|
||||||
.then(response => response.json())
|
var i = e.querySelector(".ha-filestatusicon");
|
||||||
.then(json => {
|
var a = e.querySelector(".ha-managedfileannotations");
|
||||||
document.getElementById("ha-setendyearbutton").style.pointerEvents = "auto";
|
if (value.errors === null) {
|
||||||
location.reload();
|
h.classList.add("green");
|
||||||
})
|
} else {
|
||||||
.catch ((e) => {
|
var icon = i.querySelector("svg");
|
||||||
document.getElementById("ha-setendyearbutton").style.pointerEvents = "auto";
|
icon.remove();
|
||||||
})
|
i.insertAdjacentHTML("afterbegin", '<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><title>alert-decagram-outline</title><path d="M23,12L20.56,14.78L20.9,18.46L17.29,19.28L15.4,22.46L12,21L8.6,22.47L6.71,19.29L3.1,18.47L3.44,14.78L1,12L3.44,9.21L3.1,5.53L6.71,4.72L8.6,1.54L12,3L15.4,1.54L17.29,4.72L20.9,5.54L20.56,9.22L23,12M20.33,12L18.5,9.89L18.74,7.1L16,6.5L14.58,4.07L12,5.18L9.42,4.07L8,6.5L5.26,7.09L5.5,9.88L3.67,12L5.5,14.1L5.26,16.9L8,17.5L9.42,19.93L12,18.81L14.58,19.92L16,17.5L18.74,16.89L18.5,14.1L20.33,12M11,15H13V17H11V15M11,7H13V13H11V7" /></svg>');
|
||||||
|
h.classList.add("expandable");
|
||||||
|
h.classList.add("orange");
|
||||||
|
h.addEventListener("click", () => {
|
||||||
|
h.classList.toggle("expanded");
|
||||||
|
});
|
||||||
|
var t = document.createElement("table");
|
||||||
|
var thr = document.createElement("tr");
|
||||||
|
var thl = document.createElement("th");
|
||||||
|
var thc = document.createElement("th");
|
||||||
|
var thm = document.createElement("th");
|
||||||
|
thl.append("Zeile");
|
||||||
|
thc.append("Spalte");
|
||||||
|
thm.append("Fehler");
|
||||||
|
thr.append(thl, thc, thm);
|
||||||
|
t.append(thr);
|
||||||
|
value.errors.forEach((error) => {
|
||||||
|
var tr = document.createElement("tr");
|
||||||
|
var tdl = document.createElement("td");
|
||||||
|
var tdc = document.createElement("td");
|
||||||
|
var tdm = document.createElement("td");
|
||||||
|
tdl.append(error.line);
|
||||||
|
tdc.append(error.column);
|
||||||
|
tdm.append(error.message);
|
||||||
|
tr.append(tdl, tdc, tdm);
|
||||||
|
t.append(tr);
|
||||||
|
})
|
||||||
|
a.append(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(e, h, i, a);
|
||||||
|
});
|
||||||
|
// let coll = document.getElementsByClassName("ha-managedfile");
|
||||||
|
// for (i = 0; i < coll.length; i++) {
|
||||||
|
// let e = coll[i];
|
||||||
|
// if (j[e.id] !== null) {
|
||||||
|
// if(j[e.id].errors === null) {
|
||||||
|
// console.log(e.id + " hat keine errors");
|
||||||
|
// } else {
|
||||||
|
// console.log(e.id + " hat errors");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
document.getElementById("ha-scbutton").classList.toggle("hidden");
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch ((e) => {
|
||||||
|
console.log(e);
|
||||||
|
document.getElementById("ha-scbutton").classList.toggle("loading");
|
||||||
|
document.getElementById("ha-scbutton").style.pointerEvents = "auto";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var coll = document.getElementsByClassName("expandable");
|
||||||
|
|
||||||
|
for (i = 0; i < coll.length; i++) {
|
||||||
|
let element = coll[i]
|
||||||
|
coll[i].addEventListener("click", () => {
|
||||||
|
element.classList.toggle("expanded");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -21,5 +21,6 @@ if (document.getElementById("ha-scrollbutton") !== null) {
|
|||||||
document.body.scrollTop = 0; // For Safari
|
document.body.scrollTop = 0; // For Safari
|
||||||
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
|
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
|
||||||
})
|
})
|
||||||
window.addEventListener("scroll", scrollFunction);
|
// TODO: workaround, bc window does not recieve scroll events anymore
|
||||||
|
setInterval(() => scrollFunction(), 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
157
HaWeb/wwwroot/js/websocket.js
Normal file
157
HaWeb/wwwroot/js/websocket.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
var stateSC = null;
|
||||||
|
var stateValidation = null;
|
||||||
|
var stateReload = null;
|
||||||
|
var stateCommit = null;
|
||||||
|
var firstMessage = true;
|
||||||
|
var commsLog = document.getElementById("commsLog");
|
||||||
|
var commsNot = document.getElementById("comm-notifications");
|
||||||
|
var socket;
|
||||||
|
|
||||||
|
var scheme = document.location.protocol === "https:" ? "wss" : "ws";
|
||||||
|
var port = document.location.port ? (":" + document.location.port) : "";
|
||||||
|
|
||||||
|
var connectionUrl = scheme + "://" + document.location.hostname + port + "/WS" ;
|
||||||
|
|
||||||
|
function htmlEscape(str) {
|
||||||
|
return str.toString()
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
socket = new WebSocket(connectionUrl);
|
||||||
|
socket.onopen = function (event) {
|
||||||
|
socket.send("Hello");
|
||||||
|
updateMessage();
|
||||||
|
};
|
||||||
|
socket.onclose = function (event) {
|
||||||
|
updateMessage();
|
||||||
|
};
|
||||||
|
socket.onerror = updateMessage;
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
var msg = JSON.parse(event.data);
|
||||||
|
if (msg.ValidationState != null) {
|
||||||
|
stateValidation = msg.ValidationState;
|
||||||
|
console.log(msg.ValidationState);
|
||||||
|
switch (msg.ValidationState) {
|
||||||
|
case 0:
|
||||||
|
commsNot.classList.remove("loading");
|
||||||
|
commsNot.classList.remove("green");
|
||||||
|
if (!commsNot.classList.contains("red")) {
|
||||||
|
commsNot.classList.add("red");
|
||||||
|
}
|
||||||
|
updateMessage();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (!commsNot.classList.contains("loading")) {
|
||||||
|
commsNot.classList.add("loading");
|
||||||
|
}
|
||||||
|
updateMessage();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
commsNot.classList.remove("red");
|
||||||
|
commsNot.classList.remove("loading");
|
||||||
|
if (!commsNot.classList.contains("green")) {
|
||||||
|
commsNot.classList.add("green");
|
||||||
|
}
|
||||||
|
updateMessage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (msg.Commit != null) {
|
||||||
|
stateCommit = msg;
|
||||||
|
updateMessage();
|
||||||
|
} else if (msg.reload != null) {
|
||||||
|
stateReload = msg.reload;
|
||||||
|
if (msg.reload) {
|
||||||
|
setTimeout(() => {
|
||||||
|
commsNot.remove();
|
||||||
|
socket.close(1000, "bye");
|
||||||
|
location.reload();
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (msg.SC != null) {
|
||||||
|
stateSC = msg.SC;
|
||||||
|
} else {
|
||||||
|
commsLog.innerHTML = htmlEscape(event.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateMessage() {
|
||||||
|
function disable() {
|
||||||
|
commsNot.classList.remove("red");
|
||||||
|
commsNot.classList.remove("loading");
|
||||||
|
commsNot.classList.remove("green");
|
||||||
|
}
|
||||||
|
function enable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket) {
|
||||||
|
disable();
|
||||||
|
} else {
|
||||||
|
switch (socket.readyState) {
|
||||||
|
case WebSocket.CLOSED:
|
||||||
|
commsLog.innerHTML = "Keine Verbindung";
|
||||||
|
disable();
|
||||||
|
break;
|
||||||
|
case WebSocket.CLOSING:
|
||||||
|
commsLog.innerHTML = "Verbindung wird geschlossen...";
|
||||||
|
disable();
|
||||||
|
break;
|
||||||
|
case WebSocket.CONNECTING:
|
||||||
|
commsLog.innerHTML = "Verbinden...";
|
||||||
|
disable();
|
||||||
|
break;
|
||||||
|
case WebSocket.OPEN:
|
||||||
|
commsLog.innerHTML = "";
|
||||||
|
// TODO: decide on state what the message is
|
||||||
|
if (stateValidation == 0 ) {
|
||||||
|
commsLog.innerHTML = 'Der angezeigte Stand ist nicht aktuell. ' +
|
||||||
|
'<a href="/Admin">Fehler beheben</a>';
|
||||||
|
if (!firstMessage) commsNot.classList.add("imp");
|
||||||
|
} else if (stateValidation == 1) {
|
||||||
|
commsLog.innerHTML = "Der Server arbeitet...";
|
||||||
|
} else {
|
||||||
|
if (stateCommit != null) {
|
||||||
|
commsLog.innerHTML = "commit " +
|
||||||
|
stateCommit.Commit.substring(0, 7) +
|
||||||
|
" geladen"
|
||||||
|
} else {
|
||||||
|
commsLog.innerHTML = "OK.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
firstMessage = false;
|
||||||
|
enable();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
commsLog.innerHTML = "Unknown WebSocket State: " + htmlEscape(socket.readyState);
|
||||||
|
disable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// closeButton.onclick = function () {
|
||||||
|
// if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||||
|
// alert("socket not connected");
|
||||||
|
// }
|
||||||
|
// socket.close(1000, "Closing from client");
|
||||||
|
// };
|
||||||
|
|
||||||
|
// sendButton.onclick = function () {
|
||||||
|
// if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||||
|
// alert("socket not connected");
|
||||||
|
// }
|
||||||
|
// var data = sendMessage.value;
|
||||||
|
// socket.send(data);
|
||||||
|
// commsLog.innerHTML += '<tr>' +
|
||||||
|
// '<td class="commslog-client">Client</td>' +
|
||||||
|
// '<td class="commslog-server">Server</td>' +
|
||||||
|
// '<td class="commslog-data">' + htmlEscape(data) + '</td></tr>';
|
||||||
|
// };
|
||||||
|
|
||||||
Reference in New Issue
Block a user