scaffolding for authorization.
This commit is contained in:
@@ -8,9 +8,11 @@ using System.Drawing;
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
|
[Authorize]
|
||||||
public class FilesController : Controller
|
public class FilesController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<FilesController> _logger;
|
private readonly ILogger<FilesController> _logger;
|
||||||
|
|||||||
@@ -8,31 +8,74 @@ using System.Drawing;
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
|
[Authorize]
|
||||||
public class HomeController : Controller
|
public class HomeController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<HomeController> _logger;
|
private readonly ILogger<HomeController> _logger;
|
||||||
private readonly IVehicleDataAccess _dataAccess;
|
private readonly IVehicleDataAccess _dataAccess;
|
||||||
private readonly IFileHelper _fileHelper;
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
public HomeController(ILogger<HomeController> logger, IVehicleDataAccess dataAccess, IFileHelper fileHelper)
|
public HomeController(ILogger<HomeController> logger, IVehicleDataAccess dataAccess, IFileHelper fileHelper, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_dataAccess = dataAccess;
|
_dataAccess = dataAccess;
|
||||||
_fileHelper = fileHelper;
|
_fileHelper = fileHelper;
|
||||||
|
_config = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Index()
|
public IActionResult Index(string tab = "garage")
|
||||||
{
|
{
|
||||||
return View();
|
return View(model: tab);
|
||||||
}
|
}
|
||||||
public IActionResult Garage()
|
public IActionResult Garage()
|
||||||
{
|
{
|
||||||
var vehiclesStored = _dataAccess.GetVehicles();
|
var vehiclesStored = _dataAccess.GetVehicles();
|
||||||
return PartialView("_GarageDisplay", vehiclesStored);
|
return PartialView("_GarageDisplay", vehiclesStored);
|
||||||
}
|
}
|
||||||
|
public IActionResult Settings()
|
||||||
|
{
|
||||||
|
var userConfig = new UserConfig
|
||||||
|
{
|
||||||
|
EnableCsvImports = bool.Parse(_config[nameof(UserConfig.EnableCsvImports)]),
|
||||||
|
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
|
||||||
|
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
|
||||||
|
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
|
||||||
|
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)])
|
||||||
|
};
|
||||||
|
return PartialView("_Settings", userConfig);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult WriteToSettings(UserConfig userConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var configFileContents = System.IO.File.ReadAllText("userConfig.json");
|
||||||
|
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
||||||
|
if (existingUserConfig is not null)
|
||||||
|
{
|
||||||
|
//copy over settings that are off limits on the settings page.
|
||||||
|
userConfig.EnableAuth = existingUserConfig.EnableAuth;
|
||||||
|
userConfig.UserNameHash = existingUserConfig.UserNameHash;
|
||||||
|
userConfig.UserPasswordHash = existingUserConfig.UserPasswordHash;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
userConfig.EnableAuth = false;
|
||||||
|
userConfig.UserNameHash = string.Empty;
|
||||||
|
userConfig.UserPasswordHash = string.Empty;
|
||||||
|
}
|
||||||
|
System.IO.File.WriteAllText("userConfig.json", System.Text.Json.JsonSerializer.Serialize(userConfig));
|
||||||
|
return Json(true);
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error on saving config file.");
|
||||||
|
}
|
||||||
|
return Json(false);
|
||||||
|
}
|
||||||
public IActionResult Privacy()
|
public IActionResult Privacy()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using CsvHelper;
|
using CsvHelper;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
|
[Authorize]
|
||||||
public class VehicleController : Controller
|
public class VehicleController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<HomeController> _logger;
|
private readonly ILogger<HomeController> _logger;
|
||||||
|
|||||||
43
Middleware/Authen.cs
Normal file
43
Middleware/Authen.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Middleware
|
||||||
|
{
|
||||||
|
public class Authen : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||||
|
{
|
||||||
|
private IHttpContextAccessor _httpContext;
|
||||||
|
private bool enableAuth;
|
||||||
|
public Authen(
|
||||||
|
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
ILoggerFactory logger,
|
||||||
|
IConfiguration configuration,
|
||||||
|
IHttpContextAccessor httpContext): base(options, logger, encoder)
|
||||||
|
{
|
||||||
|
_httpContext = httpContext;
|
||||||
|
enableAuth = bool.Parse(configuration["EnableAuth"]);
|
||||||
|
}
|
||||||
|
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
if (!enableAuth)
|
||||||
|
{
|
||||||
|
//generate a fake user ticket to go with it lol.
|
||||||
|
var appIdentity = new ClaimsIdentity("Custom");
|
||||||
|
var userIdentity = new List<Claim>
|
||||||
|
{
|
||||||
|
new(ClaimTypes.Name, "admin")
|
||||||
|
};
|
||||||
|
appIdentity.AddClaims(userIdentity);
|
||||||
|
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
||||||
|
return AuthenticateResult.Success(ticket);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return AuthenticateResult.Fail("Invalid credentials");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Models/UserConfig.cs
Normal file
13
Models/UserConfig.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class UserConfig
|
||||||
|
{
|
||||||
|
public bool UseDarkMode { get; set; }
|
||||||
|
public bool EnableCsvImports { get; set; }
|
||||||
|
public bool UseMPG { get; set; }
|
||||||
|
public bool UseDescending { get; set; }
|
||||||
|
public bool EnableAuth { get; set; }
|
||||||
|
public string UserNameHash { get; set; }
|
||||||
|
public string UserPasswordHash { get; set;}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Program.cs
19
Program.cs
@@ -1,6 +1,9 @@
|
|||||||
using CarCareTracker.External.Implementations;
|
using CarCareTracker.External.Implementations;
|
||||||
using CarCareTracker.External.Interfaces;
|
using CarCareTracker.External.Interfaces;
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Middleware;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@@ -14,13 +17,21 @@ builder.Services.AddSingleton<ICollisionRecordDataAccess, CollisionRecordDataAcc
|
|||||||
builder.Services.AddSingleton<ITaxRecordDataAccess, TaxRecordDataAccess>();
|
builder.Services.AddSingleton<ITaxRecordDataAccess, TaxRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
||||||
|
|
||||||
|
//Additional JsonFile
|
||||||
|
builder.Configuration.AddJsonFile("userConfig.json", optional: true, reloadOnChange: true);
|
||||||
|
|
||||||
|
//Configure Auth
|
||||||
|
builder.Services.AddHttpContextAccessor();
|
||||||
|
builder.Services.AddAuthentication("AuthN").AddScheme<AuthenticationSchemeOptions, Authen>("AuthN", opts => { });
|
||||||
|
builder.Services.AddAuthorization(options =>
|
||||||
|
{
|
||||||
|
options.DefaultPolicy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes("AuthN").RequireAuthenticatedUser().Build();
|
||||||
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (!app.Environment.IsDevelopment())
|
app.UseExceptionHandler("/Home/Error");
|
||||||
{
|
|
||||||
app.UseExceptionHandler("/Home/Error");
|
|
||||||
}
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"applicationUrl": "http://10.10.2.61:5011"
|
"applicationUrl": "http://10.10.2.60:5011"
|
||||||
},
|
},
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@{
|
@model string
|
||||||
|
@{
|
||||||
ViewData["Title"] = "LubeLogger";
|
ViewData["Title"] = "LubeLogger";
|
||||||
}
|
}
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
@@ -13,20 +14,20 @@
|
|||||||
<hr />
|
<hr />
|
||||||
<ul class="nav nav-tabs" id="homeTab" role="tablist">
|
<ul class="nav nav-tabs" id="homeTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link active" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab" aria-selected="true"><i class="bi bi-car-front me-2"></i>Garage</button>
|
<button class="nav-link @(Model == "garage" ? "active" : "")" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front me-2"></i>Garage</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item ms-auto" role="presentation">
|
<li class="nav-item ms-auto" role="presentation">
|
||||||
<button class="nav-link" id="help-tab" data-bs-toggle="tab" data-bs-target="#help-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-question-circle me-2"></i>Help</button>
|
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear me-2"></i>Settings</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="homeTab">
|
<div class="tab-content" id="homeTab">
|
||||||
<div class="tab-pane fade show active" id="garage-tab-pane" role="tabpanel" tabindex="0">
|
<div class="tab-pane fade @(Model == "garage" ? "show active" : "")" id="garage-tab-pane" role="tabpanel" tabindex="0">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div id="garageContainer" class="row gy-3 align-items-stretch">
|
<div id="garageContainer" class="row gy-3 align-items-stretch">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="help-tab-pane" role="tabpanel" tabindex="0">
|
<div class="tab-pane fade @(Model == "settings" ? "show active" : "")" id="settings-tab-pane" role="tabpanel" tabindex="0">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,4 +39,8 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
loadGarage();
|
||||||
|
loadSettings();
|
||||||
|
</script>
|
||||||
89
Views/Home/_Settings.cshtml
Normal file
89
Views/Home/_Settings.cshtml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@model UserConfig
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<h6 class="display-6 mt-2">Settings</h6>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableDarkMode" checked="@Model.UseDarkMode">
|
||||||
|
<label class="form-check-label" for="enableDarkMode">Dark Mode</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableCsvImports" checked="@Model.EnableCsvImports">
|
||||||
|
<label class="form-check-label" for="enableCsvImports">Enable CSV Imports</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useMPG" checked="@Model.UseMPG">
|
||||||
|
<label class="form-check-label" for="useMPG">Use Imperial Units for Fuel Economy Calculations(Miles, Gallons)</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="useDescending" checked="@Model.UseDescending">
|
||||||
|
<label class="form-check-label" for="useDescending">Sort lists in Descending Order(Newest to Oldest)</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableAuth" checked="@Model.EnableAuth">
|
||||||
|
<label class="form-check-label" for="enableAuth">Enable Authentication</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<h6 class="display-6 mt-2">About</h6>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<img src="/defaults/lubelogger_logo.png" />
|
||||||
|
</div>
|
||||||
|
<p class="lead">
|
||||||
|
Proudly developed in the rural town of Price, Utah by Hargata Softworks.
|
||||||
|
</p>
|
||||||
|
<p class="lead">If you enjoyed using this app, please consider spreading the good word.</p>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<h6 class="display-7 mt-2">Hometown Shoutout</h6>
|
||||||
|
</div>
|
||||||
|
<p class="lead">
|
||||||
|
Do you work remotely and are looking for a new place to call home? Consider looking into the rural Eastern Utah town of Price. Price and Carbon County
|
||||||
|
has experienced pronounced decline in both population and economic activity within the past decade whereas the rest of the state experienced exponential growth.
|
||||||
|
It is conveniently located in between Salt Lake City and Moab Utah. Amenities are relatively complete in terms of big box stores and high speed fiber Internet.
|
||||||
|
Price and its surrounding towns as a whole could really benefit from in-migration. Thank you!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<h6 class="display-7 mt-2">Open Source Dependencies</h6>
|
||||||
|
</div>
|
||||||
|
<p class="lead">
|
||||||
|
LubeLogger utilizes open-source dependencies to serve you the best possible user experience, those dependencies are:
|
||||||
|
</p>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">Bootstrap</li>
|
||||||
|
<li class="list-group-item">Bootstrap-DatePicker</li>
|
||||||
|
<li class="list-group-item">LiteDB</li>
|
||||||
|
<li class="list-group-item">SweetAlert2</li>
|
||||||
|
<li class="list-group-item">CsvHelper</li>
|
||||||
|
<li class="list-group-item">Chart.js</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function updateSettings(){
|
||||||
|
var userConfigObject = {
|
||||||
|
useDarkMode: $("#enableDarkMode").is(':checked'),
|
||||||
|
enableCsvImports: $("#enableCsvImports").is(':checked'),
|
||||||
|
useMPG: $("#useMPG").is(':checked'),
|
||||||
|
useDescending: $("#useDescending").is(':checked')
|
||||||
|
}
|
||||||
|
$.post('/Home/WriteToSettings', { userConfig: userConfigObject}, function(data){
|
||||||
|
if (data) {
|
||||||
|
setTimeout(function () { window.location.href = '/Home/Index?tab=settings' }, 500);
|
||||||
|
} else {
|
||||||
|
errorToast("An error occurred, please try again later.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@{
|
@{
|
||||||
var useDarkMode = bool.Parse(Configuration["DarkMode"]);
|
var useDarkMode = bool.Parse(Configuration["UseDarkMode"]);
|
||||||
|
var enableCsvImports = bool.Parse(Configuration["EnableCsvImports"]);
|
||||||
}
|
}
|
||||||
<html lang="en" data-bs-theme="@(useDarkMode ? "dark" : "light")">
|
<html lang="en" data-bs-theme="@(useDarkMode ? "dark" : "light")">
|
||||||
<head>
|
<head>
|
||||||
@@ -20,6 +21,14 @@
|
|||||||
<script src="~/lib/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>
|
<script src="~/lib/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>
|
||||||
<script src="~/sweetalert/sweetalert2.all.min.js"></script>
|
<script src="~/sweetalert/sweetalert2.all.min.js"></script>
|
||||||
<script src="~/js/loader.js"></script>
|
<script src="~/js/loader.js"></script>
|
||||||
|
<script>
|
||||||
|
function getGlobalConfig() {
|
||||||
|
return {
|
||||||
|
useDarkMode : "@useDarkMode" == "True",
|
||||||
|
enableCsvImport : "@enableCsvImports" == "True"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@await RenderSectionAsync("Scripts", required: false)
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<button onclick="returnToGarage()" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></button>
|
<button onclick="returnToGarage()" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></button>
|
||||||
<h1 class="text-truncate">@($"{Model.Year} {Model.Make} {Model.Model}(License # {Model.LicensePlate})")</h1>
|
<h1 class="text-truncate display-4">@($"{Model.Year} {Model.Make} {Model.Model}")<small class="text-body-secondary">@($"(#{Model.LicensePlate})")</small></h1>
|
||||||
<button onclick="editVehicle(@Model.Id)" class="btn btn-warning btn-md mt-1 mb-1"><i class="bi bi-pencil-square"></i></button>
|
<button onclick="editVehicle(@Model.Id)" class="btn btn-warning btn-md mt-1 mb-1"><i class="bi bi-pencil-square"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<script>
|
<script>
|
||||||
renderChart();
|
renderChart();
|
||||||
function renderChart() {
|
function renderChart() {
|
||||||
|
var useDarkMode = getGlobalConfig().useDarkMode;
|
||||||
new Chart($("#pie-chart"), {
|
new Chart($("#pie-chart"), {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
@@ -25,13 +26,13 @@
|
|||||||
legend: {
|
legend: {
|
||||||
position: "bottom",
|
position: "bottom",
|
||||||
labels: {
|
labels: {
|
||||||
color: "#fff"
|
color: useDarkMode ? "#fff" : "#000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: "Expenses by Type",
|
text: "Expenses by Type",
|
||||||
color: "#fff"
|
color: useDarkMode ? "#fff" : "#000"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
function renderChart() {
|
function renderChart() {
|
||||||
var barGraphLabels = [];
|
var barGraphLabels = [];
|
||||||
var barGraphData = [];
|
var barGraphData = [];
|
||||||
|
var useDarkMode = getGlobalConfig().useDarkMode;
|
||||||
@foreach (GasCostForVehicleByMonth gasCost in Model)
|
@foreach (GasCostForVehicleByMonth gasCost in Model)
|
||||||
{
|
{
|
||||||
@:barGraphLabels.push("@gasCost.MonthName");
|
@:barGraphLabels.push("@gasCost.MonthName");
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
plugins: {
|
plugins: {
|
||||||
legend: {
|
legend: {
|
||||||
labels: {
|
labels: {
|
||||||
color: '#fff'
|
color: useDarkMode ? "#fff" : "#000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -34,12 +35,12 @@
|
|||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
ticks: {
|
ticks: {
|
||||||
color: "#fff"
|
color: useDarkMode ? "#fff" : "#000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
x: {
|
x: {
|
||||||
ticks: {
|
ticks: {
|
||||||
color: "#fff"
|
color: useDarkMode ? "#fff" : "#000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"DarkMode": true,
|
"UseDarkMode": false,
|
||||||
"EnableCsvImports": true
|
"EnableCsvImports": true,
|
||||||
|
"UseMPG": true,
|
||||||
|
"UseDescending": false,
|
||||||
|
"EnableAuth": false,
|
||||||
|
"UserNameHash": "",
|
||||||
|
"UserPasswordHash": ""
|
||||||
}
|
}
|
||||||
|
|||||||
1
userConfig.json
Normal file
1
userConfig.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"UseDarkMode":true,"EnableCsvImports":true,"UseMPG":true,"UseDescending":false,"EnableAuth":false,"UserNameHash":"","UserPasswordHash":""}
|
||||||
@@ -43,4 +43,16 @@ html {
|
|||||||
|
|
||||||
.vehicleNoteContainer{
|
.vehicleNoteContainer{
|
||||||
height:40vh;
|
height:40vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-7 {
|
||||||
|
font-size: calc(1.325rem + 0.9vw);
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.display-7 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,12 +10,14 @@
|
|||||||
function hideAddVehicleModal() {
|
function hideAddVehicleModal() {
|
||||||
$('#addVehicleModal').modal('hide');
|
$('#addVehicleModal').modal('hide');
|
||||||
}
|
}
|
||||||
$(document).ready(function () {
|
|
||||||
loadGarage();
|
|
||||||
});
|
|
||||||
//refreshable function to reload Garage PartialView
|
//refreshable function to reload Garage PartialView
|
||||||
function loadGarage() {
|
function loadGarage() {
|
||||||
$.get('/Home/Garage', function (data) {
|
$.get('/Home/Garage', function (data) {
|
||||||
$("#garageContainer").html(data);
|
$("#garageContainer").html(data);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
function loadSettings() {
|
||||||
|
$.get('/Home/Settings', function (data) {
|
||||||
|
$("#settings-tab-pane").html(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user