Server Settings: Customize instance name and add contact URL (#5718)

* Server Settings: Customize instance name and add contact URL

- The custom instance name would improve #5563
- Added contact URL closes #4806

* Fix custom logo display
This commit is contained in:
d11n
2024-02-21 20:54:39 +01:00
committed by GitHub
parent 147c6c4548
commit 4ae1046571
14 changed files with 206 additions and 102 deletions

View File

@@ -252,7 +252,7 @@
{ {
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4"> <ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
<li class="nav-item" permission="@Policies.CanModifyServerSettings"> <li class="nav-item" permission="@Policies.CanModifyServerSettings">
<a asp-area="" asp-controller="UIServer" asp-action="ListUsers" class="nav-link @ViewData.IsActivePage(ServerNavPages.Users) @ViewData.IsActivePage(ServerNavPages.Emails) @ViewData.IsActivePage(ServerNavPages.Policies) @ViewData.IsActivePage(ServerNavPages.Services) @ViewData.IsActivePage(ServerNavPages.Theme) @ViewData.IsActivePage(ServerNavPages.Maintenance) @ViewData.IsActivePage(ServerNavPages.Logs) @ViewData.IsActivePage(ServerNavPages.Files)" id="Nav-ServerSettings"> <a asp-area="" asp-controller="UIServer" asp-action="ListUsers" class="nav-link @ViewData.IsActivePage(ServerNavPages.Users) @ViewData.IsActivePage(ServerNavPages.Emails) @ViewData.IsActivePage(ServerNavPages.Policies) @ViewData.IsActivePage(ServerNavPages.Services) @ViewData.IsActivePage(ServerNavPages.Branding) @ViewData.IsActivePage(ServerNavPages.Maintenance) @ViewData.IsActivePage(ServerNavPages.Logs) @ViewData.IsActivePage(ServerNavPages.Files)" id="Nav-ServerSettings">
<vc:icon symbol="server-settings"/> <vc:icon symbol="server-settings"/>
<span>Server Settings</span> <span>Server Settings</span>
</a> </a>

View File

@@ -150,6 +150,7 @@ namespace BTCPayServer.Controllers
} }
if (!ModelState.IsValid) if (!ModelState.IsValid)
return View(vm); return View(vm);
if (command == "changedomain") if (command == "changedomain")
{ {
if (string.IsNullOrWhiteSpace(vm.DNSDomain)) if (string.IsNullOrWhiteSpace(vm.DNSDomain))
@@ -995,143 +996,167 @@ namespace BTCPayServer.Controllers
return RedirectToAction(nameof(Services)); return RedirectToAction(nameof(Services));
} }
[HttpGet("server/theme")] [HttpGet("server/branding")]
public async Task<IActionResult> Theme() public async Task<IActionResult> Branding()
{ {
var data = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings(); var server = await _SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
return View(data); var theme = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
var vm = new BrandingViewModel
{
ServerName = server.ServerName,
ContactUrl = server.ContactUrl,
CustomTheme = theme.CustomTheme,
CustomThemeExtension = theme.CustomThemeExtension,
CustomThemeCssUri = theme.CustomThemeCssUri,
CustomThemeFileId = theme.CustomThemeFileId,
LogoFileId = theme.LogoFileId
};
return View(vm);
} }
[HttpPost("server/theme")] [HttpPost("server/branding")]
public async Task<IActionResult> Theme( public async Task<IActionResult> Branding(
ThemeSettings model, BrandingViewModel vm,
[FromForm] bool RemoveLogoFile, [FromForm] bool RemoveLogoFile,
[FromForm] bool RemoveCustomThemeFile) [FromForm] bool RemoveCustomThemeFile)
{ {
var settingsChanged = false; var settingsChanged = false;
var settings = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings(); var server = await _SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
var theme = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
var userId = GetUserId(); var userId = GetUserId();
if (userId is null) if (userId is null)
return NotFound(); return NotFound();
if (model.CustomThemeFile != null) vm.LogoFileId = theme.LogoFileId;
vm.CustomThemeFileId = theme.CustomThemeFileId;
if (server.ServerName != vm.ServerName || server.ContactUrl != vm.ContactUrl)
{ {
if (model.CustomThemeFile.ContentType.Equals("text/css", StringComparison.InvariantCulture)) server.ServerName = vm.ServerName;
server.ContactUrl = vm.ContactUrl;
settingsChanged = true;
await _SettingsRepository.UpdateSetting(server);
}
if (vm.CustomThemeFile != null)
{
if (vm.CustomThemeFile.ContentType.Equals("text/css", StringComparison.InvariantCulture))
{ {
// delete existing file // delete existing file
if (!string.IsNullOrEmpty(settings.CustomThemeFileId)) if (!string.IsNullOrEmpty(theme.CustomThemeFileId))
{ {
await _fileService.RemoveFile(settings.CustomThemeFileId, userId); await _fileService.RemoveFile(theme.CustomThemeFileId, userId);
} }
// add new file // add new file
try try
{ {
var storedFile = await _fileService.AddFile(model.CustomThemeFile, userId); var storedFile = await _fileService.AddFile(vm.CustomThemeFile, userId);
settings.CustomThemeFileId = storedFile.Id; vm.CustomThemeFileId = theme.CustomThemeFileId = storedFile.Id;
settingsChanged = true; settingsChanged = true;
} }
catch (Exception e) catch (Exception e)
{ {
ModelState.AddModelError(nameof(settings.CustomThemeFile), $"Could not save theme file: {e.Message}"); ModelState.AddModelError(nameof(vm.CustomThemeFile), $"Could not save theme file: {e.Message}");
} }
} }
else else
{ {
ModelState.AddModelError(nameof(settings.CustomThemeFile), "The uploaded theme file needs to be a CSS file"); ModelState.AddModelError(nameof(vm.CustomThemeFile), "The uploaded theme file needs to be a CSS file");
} }
} }
else if (RemoveCustomThemeFile && !string.IsNullOrEmpty(settings.CustomThemeFileId)) else if (RemoveCustomThemeFile && !string.IsNullOrEmpty(theme.CustomThemeFileId))
{ {
await _fileService.RemoveFile(settings.CustomThemeFileId, userId); await _fileService.RemoveFile(theme.CustomThemeFileId, userId);
settings.CustomThemeFileId = null; vm.CustomThemeFileId = theme.CustomThemeFileId = null;
settingsChanged = true; settingsChanged = true;
} }
if (model.LogoFile != null) if (vm.LogoFile != null)
{ {
if (model.LogoFile.Length > 1_000_000) if (vm.LogoFile.Length > 1_000_000)
{ {
ModelState.AddModelError(nameof(model.LogoFile), "The uploaded logo file should be less than 1MB"); ModelState.AddModelError(nameof(vm.LogoFile), "The uploaded logo file should be less than 1MB");
} }
else if (!model.LogoFile.ContentType.StartsWith("image/", StringComparison.InvariantCulture)) else if (!vm.LogoFile.ContentType.StartsWith("image/", StringComparison.InvariantCulture))
{ {
ModelState.AddModelError(nameof(model.LogoFile), "The uploaded logo file needs to be an image"); ModelState.AddModelError(nameof(vm.LogoFile), "The uploaded logo file needs to be an image");
} }
else else
{ {
var formFile = await model.LogoFile.Bufferize(); var formFile = await vm.LogoFile.Bufferize();
if (!FileTypeDetector.IsPicture(formFile.Buffer, formFile.FileName)) if (!FileTypeDetector.IsPicture(formFile.Buffer, formFile.FileName))
{ {
ModelState.AddModelError(nameof(model.LogoFile), "The uploaded logo file needs to be an image"); ModelState.AddModelError(nameof(vm.LogoFile), "The uploaded logo file needs to be an image");
} }
else else
{ {
model.LogoFile = formFile; vm.LogoFile = formFile;
// delete existing file // delete existing file
if (!string.IsNullOrEmpty(settings.LogoFileId)) if (!string.IsNullOrEmpty(theme.LogoFileId))
{ {
await _fileService.RemoveFile(settings.LogoFileId, userId); await _fileService.RemoveFile(theme.LogoFileId, userId);
} }
// add new file // add new file
try try
{ {
var storedFile = await _fileService.AddFile(model.LogoFile, userId); var storedFile = await _fileService.AddFile(vm.LogoFile, userId);
settings.LogoFileId = storedFile.Id; vm.LogoFileId = theme.LogoFileId = storedFile.Id;
settingsChanged = true; settingsChanged = true;
} }
catch (Exception e) catch (Exception e)
{ {
ModelState.AddModelError(nameof(settings.LogoFile), $"Could not save logo: {e.Message}"); ModelState.AddModelError(nameof(vm.LogoFile), $"Could not save logo: {e.Message}");
} }
} }
} }
} }
else if (RemoveLogoFile && !string.IsNullOrEmpty(settings.LogoFileId)) else if (RemoveLogoFile && !string.IsNullOrEmpty(theme.LogoFileId))
{ {
await _fileService.RemoveFile(settings.LogoFileId, userId); await _fileService.RemoveFile(theme.LogoFileId, userId);
settings.LogoFileId = null; vm.LogoFileId = theme.LogoFileId = null;
settingsChanged = true; settingsChanged = true;
} }
if (model.CustomTheme && !string.IsNullOrEmpty(model.CustomThemeCssUri) && !Uri.IsWellFormedUriString(model.CustomThemeCssUri, UriKind.RelativeOrAbsolute)) if (vm.CustomTheme && !string.IsNullOrEmpty(vm.CustomThemeCssUri) && !Uri.IsWellFormedUriString(vm.CustomThemeCssUri, UriKind.RelativeOrAbsolute))
{ {
ModelState.AddModelError(nameof(settings.CustomThemeCssUri), "Please provide a non-empty theme URI"); ModelState.AddModelError(nameof(theme.CustomThemeCssUri), "Please provide a non-empty theme URI");
} }
else if (settings.CustomThemeCssUri != model.CustomThemeCssUri) else if (theme.CustomThemeCssUri != vm.CustomThemeCssUri)
{ {
settings.CustomThemeCssUri = model.CustomThemeCssUri; theme.CustomThemeCssUri = vm.CustomThemeCssUri;
settingsChanged = true; settingsChanged = true;
} }
if (settings.CustomThemeExtension != model.CustomThemeExtension) if (theme.CustomThemeExtension != vm.CustomThemeExtension)
{ {
// Require a custom theme to be defined in that case // Require a custom theme to be defined in that case
if (string.IsNullOrEmpty(model.CustomThemeCssUri) && string.IsNullOrEmpty(settings.CustomThemeFileId)) if (string.IsNullOrEmpty(vm.CustomThemeCssUri) && string.IsNullOrEmpty(theme.CustomThemeFileId))
{ {
ModelState.AddModelError(nameof(settings.CustomThemeFile), "Please provide a custom theme"); ModelState.AddModelError(nameof(vm.CustomThemeFile), "Please provide a custom theme");
} }
else else
{ {
settings.CustomThemeExtension = model.CustomThemeExtension; theme.CustomThemeExtension = vm.CustomThemeExtension;
settingsChanged = true; settingsChanged = true;
} }
} }
if (settings.CustomTheme != model.CustomTheme) if (theme.CustomTheme != vm.CustomTheme)
{ {
settings.CustomTheme = model.CustomTheme; theme.CustomTheme = vm.CustomTheme;
settingsChanged = true; settingsChanged = true;
} }
if (settingsChanged) if (settingsChanged)
{ {
await _SettingsRepository.UpdateSetting(settings); await _SettingsRepository.UpdateSetting(theme);
TempData[WellKnownTempData.SuccessMessage] = "Theme settings updated successfully"; TempData[WellKnownTempData.SuccessMessage] = "Settings updated successfully";
} }
return View(settings); return View(vm);
} }
[Route("server/emails")] [Route("server/emails")]

View File

@@ -0,0 +1,40 @@
using System.ComponentModel.DataAnnotations;
using BTCPayServer.Services;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
namespace BTCPayServer.Models.ServerViewModels;
public class BrandingViewModel
{
// Server
[Display(Name = "Server Name")]
public string ServerName { get; set; }
[Display(Name = "Contact URL")]
public string ContactUrl { get; set; }
// Theme
[Display(Name = "Use custom theme")]
public bool CustomTheme { get; set; }
[Display(Name = "Custom Theme Extension Type")]
public ThemeExtension CustomThemeExtension { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[MaxLength(500)]
[Display(Name = "Custom Theme CSS URL")]
public string CustomThemeCssUri { get; set; }
[Display(Name = "Custom Theme File")]
[JsonIgnore]
public IFormFile CustomThemeFile { get; set; }
public string CustomThemeFileId { get; set; }
[Display(Name = "Logo")]
[JsonIgnore]
public IFormFile LogoFile { get; set; }
public string LogoFileId { get; set; }
}

View File

@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
namespace BTCPayServer.Services;
public class ServerSettings
{
[Display(Name = "Server Name")]
public string ServerName { get; set; }
[Display(Name = "Contact URL")]
public string ContactUrl { get; set; }
}

View File

@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BTCPayServer.Services; namespace BTCPayServer.Services;
@@ -27,16 +26,8 @@ public class ThemeSettings
[Display(Name = "Custom Theme CSS URL")] [Display(Name = "Custom Theme CSS URL")]
public string CustomThemeCssUri { get; set; } public string CustomThemeCssUri { get; set; }
[Display(Name = "Custom Theme File")]
[JsonIgnore]
public IFormFile CustomThemeFile { get; set; }
public string CustomThemeFileId { get; set; } public string CustomThemeFileId { get; set; }
[Display(Name = "Logo")]
[JsonIgnore]
public IFormFile LogoFile { get; set; }
public string LogoFileId { get; set; } public string LogoFileId { get; set; }
public bool FirstRun { get; set; } public bool FirstRun { get; set; }

View File

@@ -3,6 +3,7 @@
@using System.IO @using System.IO
@using BTCPayServer.Services @using BTCPayServer.Services
@inject IWebHostEnvironment WebHostEnvironment @inject IWebHostEnvironment WebHostEnvironment
@inject SettingsRepository SettingsRepository
@inject BTCPayServerEnvironment Env @inject BTCPayServerEnvironment Env
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
@{ @{
@@ -12,6 +13,7 @@
async Task<string> GetDynamicManifest(string title) async Task<string> GetDynamicManifest(string title)
{ {
var settings = await SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
var manifest = WebHostEnvironment.WebRootFileProvider.GetFileInfo("manifest.json"); var manifest = WebHostEnvironment.WebRootFileProvider.GetFileInfo("manifest.json");
if (!manifest.Exists) if (!manifest.Exists)
{ {
@@ -19,8 +21,9 @@
} }
using var reader = new StreamReader(manifest.CreateReadStream()); using var reader = new StreamReader(manifest.CreateReadStream());
var jObject = JObject.Parse(await reader.ReadToEndAsync()); var jObject = JObject.Parse(await reader.ReadToEndAsync());
var serverName = string.IsNullOrWhiteSpace(settings.ServerName) ? "BTCPay Server" : settings.ServerName;
jObject["short_name"] = title; jObject["short_name"] = title;
jObject["name"] = $"BTCPay Server: {title}"; jObject["name"] = $"{serverName}: {title}";
foreach (var jToken in jObject["icons"]!) foreach (var jToken in jObject["icons"]!)
{ {
var icon = (JObject)jToken; var icon = (JObject)jToken;

View File

@@ -1,7 +1,13 @@
@using BTCPayServer.Services
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Components.MainLogo
@inject SettingsRepository SettingsRepository
@{ @{
Layout = "_LayoutSimple"; Layout = "_LayoutSimple";
ViewBag.ShowTitle ??= true; ViewBag.ShowTitle ??= true;
ViewBag.ShowLeadText ??= false; ViewBag.ShowLeadText ??= false;
var settings = await SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
} }
@section PageHeadContent { @section PageHeadContent {
@@ -33,7 +39,7 @@
<vc:main-logo /> <vc:main-logo />
</a> </a>
<h1 class="h2 mb-3">Welcome to your BTCPay&nbsp;Server</h1> <h1 class="h2 mb-3">Welcome to @(string.IsNullOrWhiteSpace(settings.ServerName) ? "your BTCPay\u00a0Server" : settings.ServerName)</h1>
@if (ViewBag.ShowLeadText) @if (ViewBag.ShowLeadText)
{ {
<p class="lead"> <p class="lead">
@@ -49,11 +55,18 @@
<div class="account-form"> <div class="account-form">
@if (ViewBag.ShowTitle) @if (ViewBag.ShowTitle)
{ {
<h4 v-pre>@ViewData["Title"]</h4> <h4 v-pre>@ViewData["Title"]</h4>
} }
@RenderBody() @RenderBody()
</div> </div>
@if (!string.IsNullOrWhiteSpace(settings.ContactUrl))
{
<p class="text-center mt-n5 mb-5 pt-2">
<a class="text-secondary" href="@settings.ContactUrl" id="ContactLink">Contact Us</a>
</p>
}
<div class="row justify-content-center mt-5"> <div class="row justify-content-center mt-5">
<div class="col"> <div class="col">
<partial name="_BTCPaySupporters"/> <partial name="_BTCPaySupporters"/>

View File

@@ -3,7 +3,7 @@
} }
<style> <style>
.main-logo { height: 4rem; width: 18rem; } .main-logo { height: 4.5rem; max-width: 18rem; }
.main-logo-btcpay .main-logo-btcpay--small { display: none; } .main-logo-btcpay .main-logo-btcpay--small { display: none; }
.lead img { max-width: 100%; } .lead img { max-width: 100%; }
</style> </style>

View File

@@ -1,11 +1,15 @@
@using BTCPayServer.Services
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model HomeViewModel; @model HomeViewModel;
@inject SettingsRepository SettingsRepository
@{ @{
ViewData["Title"] = "BTCPay Server"; var settings = await SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
ViewData["Title"] = string.IsNullOrWhiteSpace(settings.ServerName) ? "BTCPay Server" : settings.ServerName;
} }
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<h2>Welcome to your BTCPay Server</h2> <h2>Welcome to @(string.IsNullOrWhiteSpace(settings.ServerName) ? "your BTCPay\u00a0Server" : settings.ServerName)</h2>
@if (!Model.HasStore) @if (!Model.HasStore)
{ {

View File

@@ -1,9 +1,9 @@
@using BTCPayServer.Abstractions.Contracts @using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Services @using BTCPayServer.Services
@model BTCPayServer.Services.ThemeSettings @model BrandingViewModel;
@inject IFileService FileService @inject IFileService FileService
@{ @{
ViewData.SetActivePage(ServerNavPages.Theme, "Theme"); ViewData.SetActivePage(ServerNavPages.Branding, "Branding");
var canUpload = await FileService.IsAvailable(); var canUpload = await FileService.IsAvailable();
var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t => var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t =>
new SelectListItem(typeof(ThemeExtension).DisplayName(t.ToString()), t == ThemeExtension.Custom ? null : t.ToString())); new SelectListItem(typeof(ThemeExtension).DisplayName(t.ToString()), t == ThemeExtension.Custom ? null : t.ToString()));
@@ -18,6 +18,51 @@
<div class="row"> <div class="row">
<div class="col-xl-8 col-xxl-constrain"> <div class="col-xl-8 col-xxl-constrain">
<form method="post" enctype="multipart/form-data"> <form method="post" enctype="multipart/form-data">
<div class="form-group">
<label asp-for="ServerName" class="form-label"></label>
<input asp-for="ServerName" class="form-control" />
<div class="form-text">You can give this server a custom name, which will appear on public facing pages.</div>
<span asp-validation-for="ServerName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ContactUrl" class="form-label"></label>
<input asp-for="ContactUrl" class="form-control" />
<div class="form-text">
Contact link for support requests related to this BTCPay Server instance.
This link will appear on public facing pages.
Can be any valid URI, such as a website, email, and Nostr.
</div>
<span asp-validation-for="ContactUrl" class="text-danger"></span>
</div>
<div class="form-group">
<div class="d-flex align-items-center justify-content-between gap-2">
<label asp-for="LogoFile" class="form-label"></label>
@if (!string.IsNullOrEmpty(Model.LogoFileId))
{
<button type="submit" class="btn btn-link p-0 text-danger" name="RemoveLogoFile" value="true">
<span class="fa fa-times"></span> Remove
</button>
}
</div>
@if (canUpload)
{
<div class="d-flex align-items-center gap-3">
<input asp-for="LogoFile" type="file" class="form-control flex-grow">
@if (!string.IsNullOrEmpty(Model.LogoFileId))
{
<img src="@(await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId))" alt="Logo" style="height:2.1rem;max-width:10.5rem;"/>
}
</div>
<span asp-validation-for="LogoFile" class="text-danger"></span>
}
else
{
<input asp-for="LogoFile" type="file" class="form-control" disabled>
<div class="form-text">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div>
}
</div>
<h3 class="mt-5 mb-3">Theme</h3>
<p>Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p> <p>Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p>
<div class="d-flex align-items-center mb-3"> <div class="d-flex align-items-center mb-3">
@@ -75,35 +120,6 @@
} }
</div> </div>
<h3 class="mt-5 mb-3">Branding</h3>
<div class="form-group">
<div class="d-flex align-items-center justify-content-between gap-2">
<label asp-for="LogoFile" class="form-label"></label>
@if (!string.IsNullOrEmpty(Model.LogoFileId))
{
<button type="submit" class="btn btn-link p-0 text-danger" name="RemoveLogoFile" value="true">
<span class="fa fa-times"></span> Remove
</button>
}
</div>
@if (canUpload)
{
<div class="d-flex align-items-center gap-3">
<input asp-for="LogoFile" type="file" class="form-control flex-grow">
@if (!string.IsNullOrEmpty(Model.LogoFileId))
{
<img src="@(await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId))" alt="Logo" style="height:2.1rem;max-width:10.5rem;"/>
}
</div>
<span asp-validation-for="LogoFile" class="text-danger"></span>
}
else
{
<input asp-for="LogoFile" type="file" class="form-control" disabled>
<div class="form-text">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div>
}
</div>
<button type="submit" class="btn btn-primary mt-2" name="command" value="Save">Save</button> <button type="submit" class="btn btn-primary mt-2" name="command" value="Save">Save</button>
</form> </form>
</div> </div>

View File

@@ -13,10 +13,8 @@
<input asp-for="DNSDomain" class="form-control" disabled="@(Model.CanUseSSH ? null : "disabled")" /> <input asp-for="DNSDomain" class="form-control" disabled="@(Model.CanUseSSH ? null : "disabled")" />
<div class="form-text">You can change the domain name of your server by following <a href="https://docs.btcpayserver.org/FAQ/Deployment/#how-to-change-your-btcpay-server-domain-name" target="_blank" rel="noreferrer noopener">this guide</a>.</div> <div class="form-text">You can change the domain name of your server by following <a href="https://docs.btcpayserver.org/FAQ/Deployment/#how-to-change-your-btcpay-server-domain-name" target="_blank" rel="noreferrer noopener">this guide</a>.</div>
<span asp-validation-for="DNSDomain" class="text-danger"></span> <span asp-validation-for="DNSDomain" class="text-danger"></span>
<button name="command" type="submit" class="btn btn-secondary mt-3" value="changedomain" title="Change domain" disabled="@(Model.CanUseSSH ? null : "disabled")">
Confirm
</button>
</div> </div>
<button name="command" type="submit" class="btn btn-secondary" value="changedomain" title="Change domain" disabled="@(Model.CanUseSSH ? null : "disabled")">Change Domain</button>
<h4 class="mt-5 mb-2">Restart</h4> <h4 class="mt-5 mb-2">Restart</h4>
<p>Restart BTCPay Server and related services.</p> <p>Restart BTCPay Server and related services.</p>

View File

@@ -2,7 +2,7 @@ namespace BTCPayServer.Views.Server
{ {
public enum ServerNavPages public enum ServerNavPages
{ {
Index, Users, Emails, Policies, Theme, Services, Maintenance, Logs, Files, Plugins, Index, Users, Emails, Policies, Branding, Services, Maintenance, Logs, Files, Plugins,
Roles Roles
} }
} }

View File

@@ -10,7 +10,7 @@
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.IsActivePage(ServerNavPages.Emails)" asp-action="Emails">Email</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.IsActivePage(ServerNavPages.Emails)" asp-action="Emails">Email</a>
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Policies" class="nav-link @ViewData.IsActivePage(ServerNavPages.Policies)" asp-action="Policies">Policies</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Policies" class="nav-link @ViewData.IsActivePage(ServerNavPages.Policies)" asp-action="Policies">Policies</a>
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.IsActivePage(ServerNavPages.Services)" asp-action="Services">Services</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.IsActivePage(ServerNavPages.Services)" asp-action="Services">Services</a>
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Theme" class="nav-link @ViewData.IsActivePage(ServerNavPages.Theme)" asp-action="Theme">Theme</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Branding" class="nav-link @ViewData.IsActivePage(ServerNavPages.Branding)" asp-action="Branding">Branding</a>
@if (_btcPayServerOptions.DockerDeployment) @if (_btcPayServerOptions.DockerDeployment)
{ {
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.IsActivePage(ServerNavPages.Maintenance)" asp-action="Maintenance">Maintenance</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.IsActivePage(ServerNavPages.Maintenance)" asp-action="Maintenance">Maintenance</a>

View File

@@ -29,8 +29,8 @@
@section PageHeadContent { @section PageHeadContent {
<style> <style>
#FirstStore { max-width: 27rem; margin: 0 auto; text-align: center; } #FirstStore { max-width: 27rem; margin: 0 auto; text-align: center; }
#FirstStore .main-logo { height: 4rem; width: 18rem; } #FirstStore .main-logo { height: 4.5rem; max-width: 18rem; }
#FirstStore .main-logo.main-logo-btcpay { height: 4.5rem; width: 2.5rem; } #FirstStore .main-logo.main-logo-btcpay { width: 2.5rem; }
#FirstStore .main-logo-btcpay .main-logo-btcpay--large { display: none; } #FirstStore .main-logo-btcpay .main-logo-btcpay--large { display: none; }
#FirstStore .form-control, #FirstStore .form-select { width: 100%; } #FirstStore .form-control, #FirstStore .form-select { width: 100%; }
#FirstStore .form-text { font-size: var(--btcpay-font-size-s); } #FirstStore .form-text { font-size: var(--btcpay-font-size-s); }