Added swagger and elmah return-to-front-end button
This commit is contained in:
@@ -15,6 +15,7 @@ using Microsoft.OpenApi.Models;
|
|||||||
using Shared.Models;
|
using Shared.Models;
|
||||||
using Microsoft.AspNetCore.ResponseCompression;
|
using Microsoft.AspNetCore.ResponseCompression;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@@ -141,6 +142,57 @@ var app = builder.Build();
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
// Configure Elmah
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
if (context.Request.Path.StartsWithSegments("/elmah"))
|
||||||
|
{
|
||||||
|
context.Response.OnStarting(() =>
|
||||||
|
{
|
||||||
|
context.Response.Headers.Append(
|
||||||
|
"Content-Security-Policy",
|
||||||
|
"default-src 'self' 'unsafe-inline' 'unsafe-eval'"
|
||||||
|
);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
if (!context.Request.Path.StartsWithSegments("/elmah"))
|
||||||
|
{
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var originalBody = context.Response.Body;
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
context.Response.Body = memStream;
|
||||||
|
|
||||||
|
await next();
|
||||||
|
|
||||||
|
memStream.Position = 0;
|
||||||
|
var html = await new StreamReader(memStream).ReadToEndAsync();
|
||||||
|
|
||||||
|
if (context.Response.ContentType?.Contains("text/html") == true)
|
||||||
|
{
|
||||||
|
html = html.Replace(
|
||||||
|
"</head>",
|
||||||
|
"""
|
||||||
|
<link rel="stylesheet" href="/elmah-ui/custom.css" />
|
||||||
|
<script src="/elmah-ui/custom.js"></script>
|
||||||
|
</head>
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(html);
|
||||||
|
context.Response.ContentLength = bytes.Length;
|
||||||
|
await originalBody.WriteAsync(bytes);
|
||||||
|
context.Response.Body = originalBody;
|
||||||
|
});
|
||||||
app.UseElmah();
|
app.UseElmah();
|
||||||
|
|
||||||
app.MapHealthChecks("/healthz");
|
app.MapHealthChecks("/healthz");
|
||||||
@@ -180,6 +232,8 @@ app.UseSwagger();
|
|||||||
app.UseSwaggerUI(options =>
|
app.UseSwaggerUI(options =>
|
||||||
{
|
{
|
||||||
options.EnablePersistAuthorization();
|
options.EnablePersistAuthorization();
|
||||||
|
options.InjectStylesheet("/swagger-ui/custom.css");
|
||||||
|
options.InjectJavascript("/swagger-ui/custom.js");
|
||||||
});
|
});
|
||||||
//app.UseElmahExceptionPage(); // Messes with JSON response for API calls. Leaving this here so I don't accidentally put this in again later on.
|
//app.UseElmahExceptionPage(); // Messes with JSON response for API calls. Leaving this here so I don't accidentally put this in again later on.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@using Server.Services
|
@using Server.Services
|
||||||
|
@using System.Net
|
||||||
@inject LocalizationService T
|
@inject LocalizationService T
|
||||||
|
@{
|
||||||
|
var currentUrl = WebUtility.HtmlEncode(Context.Request.Path);
|
||||||
|
}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName">
|
<html lang="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName">
|
||||||
<head>
|
<head>
|
||||||
@@ -59,6 +62,18 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Searchdomains">@T["Searchdomains"]</a>
|
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Searchdomains">@T["Searchdomains"]</a>
|
||||||
</li>
|
</li>
|
||||||
|
@if (User.IsInRole("Admin") || User.IsInRole("Swagger"))
|
||||||
|
{
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-dark" href="/swagger/index.html?ReturnUrl=@(currentUrl)">@T["Swagger"]</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@if (User.IsInRole("Admin"))
|
||||||
|
{
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-dark" href="/elmah?ReturnUrl=@(currentUrl)">@T["Elmah"]</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Logout">@T["Logout"]</a>
|
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Logout">@T["Logout"]</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
54
src/Server/wwwroot/elmah-ui/custom.css
Normal file
54
src/Server/wwwroot/elmah-ui/custom.css
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
.elmah-return-btn {
|
||||||
|
position: fixed;
|
||||||
|
top: 6px;
|
||||||
|
right: 24px;
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
height: 44px;
|
||||||
|
min-width: 44px;
|
||||||
|
padding: 0 14px;
|
||||||
|
|
||||||
|
background: #85ea2d;
|
||||||
|
color: black;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
justify-content: center;
|
||||||
|
text-decoration: none !important;
|
||||||
|
|
||||||
|
transition:
|
||||||
|
top 0.25s ease,
|
||||||
|
background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hidden label */
|
||||||
|
.elmah-return-btn::before {
|
||||||
|
content: "Return to Front-end";
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
max-width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition:
|
||||||
|
max-width 0.3s ease,
|
||||||
|
opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* expand on hover */
|
||||||
|
.elmah-return-btn:hover::before {
|
||||||
|
max-width: 220px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hover colors */
|
||||||
|
.elmah-return-btn:hover {
|
||||||
|
background: #0b5ed7;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
10
src/Server/wwwroot/elmah-ui/custom.js
Normal file
10
src/Server/wwwroot/elmah-ui/custom.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const btn = document.createElement("a");
|
||||||
|
btn.href = url.searchParams.get('ReturnUrl') ?? "/";
|
||||||
|
btn.innerText = "⎋";
|
||||||
|
btn.setAttribute("aria-label", "Return to Front-End");
|
||||||
|
btn.className = "elmah-return-btn";
|
||||||
|
|
||||||
|
document.body.appendChild(btn);
|
||||||
|
});
|
||||||
58
src/Server/wwwroot/swagger-ui/custom.css
Normal file
58
src/Server/wwwroot/swagger-ui/custom.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
.swagger-return-btn {
|
||||||
|
position: fixed;
|
||||||
|
top: 6px;
|
||||||
|
left: 24px;
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
height: 44px;
|
||||||
|
min-width: 44px;
|
||||||
|
padding: 0 14px;
|
||||||
|
|
||||||
|
background: #85ea2d;
|
||||||
|
color: black;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
transition:
|
||||||
|
top 0.25s ease,
|
||||||
|
background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hidden label */
|
||||||
|
.swagger-return-btn::after {
|
||||||
|
content: "Return to Front-end";
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
max-width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition:
|
||||||
|
max-width 0.3s ease,
|
||||||
|
opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* expand on hover */
|
||||||
|
.swagger-return-btn:hover::after {
|
||||||
|
max-width: 220px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hover colors */
|
||||||
|
.swagger-return-btn:hover {
|
||||||
|
background: #0b5ed7;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* scrolled state */
|
||||||
|
.swagger-return-btn.scrolled {
|
||||||
|
top: 24px;
|
||||||
|
}
|
||||||
24
src/Server/wwwroot/swagger-ui/custom.js
Normal file
24
src/Server/wwwroot/swagger-ui/custom.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const btn = document.createElement("a");
|
||||||
|
btn.href = url.searchParams.get('ReturnUrl') ?? "/";
|
||||||
|
btn.innerText = "⎋";
|
||||||
|
btn.setAttribute("aria-label", "Return to Front-End");
|
||||||
|
btn.className = "swagger-return-btn";
|
||||||
|
|
||||||
|
document.body.appendChild(btn);
|
||||||
|
|
||||||
|
const togglePosition = () => {
|
||||||
|
if (window.scrollY > 0) {
|
||||||
|
btn.classList.add("scrolled");
|
||||||
|
} else {
|
||||||
|
btn.classList.remove("scrolled");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial state
|
||||||
|
togglePosition();
|
||||||
|
|
||||||
|
// On scroll
|
||||||
|
window.addEventListener("scroll", togglePosition, { passive: true });
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user