Compare commits
17 Commits
v1.4.7
...
Hargata/up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29680cf0e9 | ||
|
|
723eb1a769 | ||
|
|
732a628c20 | ||
|
|
84d40edb0e | ||
|
|
9842f0e501 | ||
|
|
44c5f921a5 | ||
|
|
fae4aa31aa | ||
|
|
adb505c87c | ||
|
|
d21b0a9e29 | ||
|
|
15e4181aff | ||
|
|
3a4627ef02 | ||
|
|
d9e11273bd | ||
|
|
8e6f40a1b1 | ||
|
|
55f86ecb3f | ||
|
|
8eef1465cf | ||
|
|
fd0ffba7c4 | ||
|
|
afb710e6ad |
@@ -112,6 +112,34 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Route("/api/version")]
|
||||||
|
public async Task<IActionResult> ServerVersion(bool checkForUpdate = false)
|
||||||
|
{
|
||||||
|
var viewModel = new ReleaseVersion
|
||||||
|
{
|
||||||
|
CurrentVersion = StaticHelper.VersionNumber,
|
||||||
|
LatestVersion = StaticHelper.VersionNumber
|
||||||
|
};
|
||||||
|
if (checkForUpdate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("request");
|
||||||
|
var releaseResponse = await httpClient.GetFromJsonAsync<ReleaseResponse>(StaticHelper.ReleasePath) ?? new ReleaseResponse();
|
||||||
|
if (!string.IsNullOrWhiteSpace(releaseResponse.tag_name))
|
||||||
|
{
|
||||||
|
viewModel.LatestVersion = releaseResponse.tag_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(OperationResponse.Failed($"Unable to retrieve latest version from GitHub API: {ex.Message}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(viewModel);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
[Route("/api/vehicles")]
|
[Route("/api/vehicles")]
|
||||||
public IActionResult Vehicles()
|
public IActionResult Vehicles()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,14 +14,15 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
//get records
|
//get records
|
||||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||||
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _vehicleLogic.GetVehicleRecords(vehicleId);
|
||||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
var serviceRecords = vehicleRecords.ServiceRecords;
|
||||||
var collisionRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
var gasRecords = vehicleRecords.GasRecords;
|
||||||
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
var collisionRecords = vehicleRecords.CollisionRecords;
|
||||||
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
var taxRecords = vehicleRecords.TaxRecords;
|
||||||
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
var upgradeRecords = vehicleRecords.UpgradeRecords;
|
||||||
|
var odometerRecords = vehicleRecords.OdometerRecords;
|
||||||
var userConfig = _config.GetUserConfig(User);
|
var userConfig = _config.GetUserConfig(User);
|
||||||
var viewModel = new ReportViewModel();
|
var viewModel = new ReportViewModel() { ReportHeaderForVehicle = new ReportHeader() };
|
||||||
//check if custom widgets are configured
|
//check if custom widgets are configured
|
||||||
viewModel.CustomWidgetsConfigured = _fileHelper.WidgetsExist();
|
viewModel.CustomWidgetsConfigured = _fileHelper.WidgetsExist();
|
||||||
//get totalCostMakeUp
|
//get totalCostMakeUp
|
||||||
@@ -91,6 +92,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
|
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||||
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||||
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleData.IsElectric, vehicleData.UseHours, userConfig.UseMPG, userConfig.UseUKMPG);
|
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleData.IsElectric, vehicleData.UseHours, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||||
|
var averageMPG = _gasHelper.GetAverageGasMileage(mileageData, userConfig.UseMPG);
|
||||||
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
||||||
bool invertedFuelMileageUnit = fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l";
|
bool invertedFuelMileageUnit = fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l";
|
||||||
var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName();
|
var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName();
|
||||||
@@ -114,6 +116,12 @@ namespace CarCareTracker.Controllers
|
|||||||
monthMileage.Cost = 100 / monthMileage.Cost;
|
monthMileage.Cost = 100 / monthMileage.Cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var newAverageMPG = decimal.Parse(averageMPG, NumberStyles.Any);
|
||||||
|
if (newAverageMPG != 0)
|
||||||
|
{
|
||||||
|
newAverageMPG = 100 / newAverageMPG;
|
||||||
|
}
|
||||||
|
averageMPG = newAverageMPG.ToString("F");
|
||||||
}
|
}
|
||||||
var mpgViewModel = new MPGForVehicleByMonth {
|
var mpgViewModel = new MPGForVehicleByMonth {
|
||||||
CostData = monthlyMileageData,
|
CostData = monthlyMileageData,
|
||||||
@@ -121,6 +129,15 @@ namespace CarCareTracker.Controllers
|
|||||||
SortedCostData = (userConfig.UseMPG || invertedFuelMileageUnit) ? monthlyMileageData.OrderByDescending(x => x.Cost).ToList() : monthlyMileageData.OrderBy(x => x.Cost).ToList()
|
SortedCostData = (userConfig.UseMPG || invertedFuelMileageUnit) ? monthlyMileageData.OrderByDescending(x => x.Cost).ToList() : monthlyMileageData.OrderBy(x => x.Cost).ToList()
|
||||||
};
|
};
|
||||||
viewModel.FuelMileageForVehicleByMonth = mpgViewModel;
|
viewModel.FuelMileageForVehicleByMonth = mpgViewModel;
|
||||||
|
//report header
|
||||||
|
|
||||||
|
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||||
|
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||||
|
|
||||||
|
viewModel.ReportHeaderForVehicle.TotalCost = _vehicleLogic.GetVehicleTotalCost(vehicleRecords);
|
||||||
|
viewModel.ReportHeaderForVehicle.AverageMPG = $"{averageMPG} {mpgViewModel.Unit}";
|
||||||
|
viewModel.ReportHeaderForVehicle.MaxOdometer = maxMileage;
|
||||||
|
viewModel.ReportHeaderForVehicle.DistanceTraveled = maxMileage - minMileage;
|
||||||
return PartialView("_Report", viewModel);
|
return PartialView("_Report", viewModel);
|
||||||
}
|
}
|
||||||
[TypeFilter(typeof(CollaboratorFilter))]
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
@@ -145,6 +162,63 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
[TypeFilter(typeof(CollaboratorFilter))]
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult GetSummaryForVehicle(int vehicleId, int year = 0)
|
||||||
|
{
|
||||||
|
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||||
|
var vehicleRecords = _vehicleLogic.GetVehicleRecords(vehicleId);
|
||||||
|
|
||||||
|
var serviceRecords = vehicleRecords.ServiceRecords;
|
||||||
|
var gasRecords = vehicleRecords.GasRecords;
|
||||||
|
var collisionRecords = vehicleRecords.CollisionRecords;
|
||||||
|
var taxRecords = vehicleRecords.TaxRecords;
|
||||||
|
var upgradeRecords = vehicleRecords.UpgradeRecords;
|
||||||
|
var odometerRecords = vehicleRecords.OdometerRecords;
|
||||||
|
|
||||||
|
if (year != default)
|
||||||
|
{
|
||||||
|
serviceRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
gasRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
collisionRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
taxRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
upgradeRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
odometerRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
}
|
||||||
|
|
||||||
|
var userConfig = _config.GetUserConfig(User);
|
||||||
|
|
||||||
|
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||||
|
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||||
|
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleData.IsElectric, vehicleData.UseHours, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||||
|
var averageMPG = _gasHelper.GetAverageGasMileage(mileageData, userConfig.UseMPG);
|
||||||
|
bool invertedFuelMileageUnit = fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l";
|
||||||
|
|
||||||
|
if (invertedFuelMileageUnit)
|
||||||
|
{
|
||||||
|
var newAverageMPG = decimal.Parse(averageMPG, NumberStyles.Any);
|
||||||
|
if (newAverageMPG != 0)
|
||||||
|
{
|
||||||
|
newAverageMPG = 100 / newAverageMPG;
|
||||||
|
}
|
||||||
|
averageMPG = newAverageMPG.ToString("F");
|
||||||
|
}
|
||||||
|
|
||||||
|
var mpgUnit = invertedFuelMileageUnit ? preferredFuelMileageUnit : fuelEconomyMileageUnit;
|
||||||
|
|
||||||
|
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||||
|
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||||
|
|
||||||
|
var viewModel = new ReportHeader()
|
||||||
|
{
|
||||||
|
TotalCost = _vehicleLogic.GetVehicleTotalCost(vehicleRecords),
|
||||||
|
AverageMPG = $"{averageMPG} {mpgUnit}",
|
||||||
|
MaxOdometer = maxMileage,
|
||||||
|
DistanceTraveled = maxMileage - minMileage
|
||||||
|
};
|
||||||
|
|
||||||
|
return PartialView("_ReportHeader", viewModel);
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetCostMakeUpForVehicle(int vehicleId, int year = 0)
|
public IActionResult GetCostMakeUpForVehicle(int vehicleId, int year = 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace CarCareTracker.Helper
|
|||||||
bool GetCustomWidgetsEnabled();
|
bool GetCustomWidgetsEnabled();
|
||||||
string GetMOTD();
|
string GetMOTD();
|
||||||
string GetLogoUrl();
|
string GetLogoUrl();
|
||||||
|
string GetSmallLogoUrl();
|
||||||
string GetServerLanguage();
|
string GetServerLanguage();
|
||||||
bool GetServerDisabledRegistration();
|
bool GetServerDisabledRegistration();
|
||||||
bool GetServerEnableShopSupplies();
|
bool GetServerEnableShopSupplies();
|
||||||
@@ -92,6 +93,11 @@ namespace CarCareTracker.Helper
|
|||||||
var logoUrl = CheckString("LUBELOGGER_LOGO_URL", "/defaults/lubelogger_logo.png");
|
var logoUrl = CheckString("LUBELOGGER_LOGO_URL", "/defaults/lubelogger_logo.png");
|
||||||
return logoUrl;
|
return logoUrl;
|
||||||
}
|
}
|
||||||
|
public string GetSmallLogoUrl()
|
||||||
|
{
|
||||||
|
var logoUrl = CheckString("LUBELOGGER_LOGO_SMALL_URL", "/defaults/lubelogger_logo_small.png");
|
||||||
|
return logoUrl;
|
||||||
|
}
|
||||||
public string GetAllowedFileUploadExtensions()
|
public string GetAllowedFileUploadExtensions()
|
||||||
{
|
{
|
||||||
var allowedFileExtensions = CheckString("LUBELOGGER_ALLOWED_FILE_EXTENSIONS", StaticHelper.DefaultAllowedFileExtensions);
|
var allowedFileExtensions = CheckString("LUBELOGGER_ALLOWED_FILE_EXTENSIONS", StaticHelper.DefaultAllowedFileExtensions);
|
||||||
@@ -252,7 +258,8 @@ namespace CarCareTracker.Helper
|
|||||||
ReminderUrgencyConfig = _config.GetSection(nameof(UserConfig.ReminderUrgencyConfig)).Get<ReminderUrgencyConfig>() ?? new ReminderUrgencyConfig(),
|
ReminderUrgencyConfig = _config.GetSection(nameof(UserConfig.ReminderUrgencyConfig)).Get<ReminderUrgencyConfig>() ?? new ReminderUrgencyConfig(),
|
||||||
DefaultTab = (ImportMode)int.Parse(CheckString(nameof(UserConfig.DefaultTab), "8")),
|
DefaultTab = (ImportMode)int.Parse(CheckString(nameof(UserConfig.DefaultTab), "8")),
|
||||||
DefaultReminderEmail = CheckString(nameof(UserConfig.DefaultReminderEmail)),
|
DefaultReminderEmail = CheckString(nameof(UserConfig.DefaultReminderEmail)),
|
||||||
DisableRegistration = CheckBool(CheckString(nameof(UserConfig.DisableRegistration)))
|
DisableRegistration = CheckBool(CheckString(nameof(UserConfig.DisableRegistration))),
|
||||||
|
ShowVehicleThumbnail = CheckBool(CheckString(nameof(UserConfig.ShowVehicleThumbnail)))
|
||||||
};
|
};
|
||||||
int userId = 0;
|
int userId = 0;
|
||||||
if (user != null)
|
if (user != null)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace CarCareTracker.Helper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StaticHelper
|
public static class StaticHelper
|
||||||
{
|
{
|
||||||
public const string VersionNumber = "1.4.7";
|
public const string VersionNumber = "1.4.8";
|
||||||
public const string DbName = "data/cartracker.db";
|
public const string DbName = "data/cartracker.db";
|
||||||
public const string UserConfigPath = "data/config/userConfig.json";
|
public const string UserConfigPath = "data/config/userConfig.json";
|
||||||
public const string LegacyUserConfigPath = "config/userConfig.json";
|
public const string LegacyUserConfigPath = "config/userConfig.json";
|
||||||
@@ -22,6 +22,7 @@ namespace CarCareTracker.Helper
|
|||||||
public const string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx";
|
public const string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx";
|
||||||
public const string SponsorsPath = "https://hargata.github.io/hargata/sponsors.json";
|
public const string SponsorsPath = "https://hargata.github.io/hargata/sponsors.json";
|
||||||
public const string TranslationPath = "https://hargata.github.io/lubelog_translations";
|
public const string TranslationPath = "https://hargata.github.io/lubelog_translations";
|
||||||
|
public const string ReleasePath = "https://api.github.com/repos/hargata/lubelog/releases/latest";
|
||||||
public const string TranslationDirectoryPath = $"{TranslationPath}/directory.json";
|
public const string TranslationDirectoryPath = $"{TranslationPath}/directory.json";
|
||||||
public const string ReportNote = "Report generated by LubeLogger, a Free and Open Source Vehicle Maintenance Tracker - LubeLogger.com";
|
public const string ReportNote = "Report generated by LubeLogger, a Free and Open Source Vehicle Maintenance Tracker - LubeLogger.com";
|
||||||
public static string GetTitleCaseReminderUrgency(ReminderUrgency input)
|
public static string GetTitleCaseReminderUrgency(ReminderUrgency input)
|
||||||
|
|||||||
18
Models/API/ReleaseVersion.cs
Normal file
18
Models/API/ReleaseVersion.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// For deserializing GitHub response for latest version
|
||||||
|
/// </summary>
|
||||||
|
public class ReleaseResponse
|
||||||
|
{
|
||||||
|
public string tag_name { get; set; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// For returning the version numbers via API.
|
||||||
|
/// </summary>
|
||||||
|
public class ReleaseVersion
|
||||||
|
{
|
||||||
|
public string CurrentVersion { get; set; }
|
||||||
|
public string LatestVersion { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Models/Report/ReportHeader.cs
Normal file
10
Models/Report/ReportHeader.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class ReportHeader
|
||||||
|
{
|
||||||
|
public int MaxOdometer { get; set; }
|
||||||
|
public int DistanceTraveled { get; set; }
|
||||||
|
public decimal TotalCost { get; set; }
|
||||||
|
public string AverageMPG { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class ReportViewModel
|
public class ReportViewModel
|
||||||
{
|
{
|
||||||
|
public ReportHeader ReportHeaderForVehicle { get; set; } = new ReportHeader();
|
||||||
public List<CostForVehicleByMonth> CostForVehicleByMonth { get; set; } = new List<CostForVehicleByMonth>();
|
public List<CostForVehicleByMonth> CostForVehicleByMonth { get; set; } = new List<CostForVehicleByMonth>();
|
||||||
public MPGForVehicleByMonth FuelMileageForVehicleByMonth { get; set; } = new MPGForVehicleByMonth();
|
public MPGForVehicleByMonth FuelMileageForVehicleByMonth { get; set; } = new MPGForVehicleByMonth();
|
||||||
public CostMakeUpForVehicle CostMakeUpForVehicle { get; set; } = new CostMakeUpForVehicle();
|
public CostMakeUpForVehicle CostMakeUpForVehicle { get; set; } = new CostMakeUpForVehicle();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
public string PreferredGasMileageUnit { get; set; } = string.Empty;
|
public string PreferredGasMileageUnit { get; set; } = string.Empty;
|
||||||
public bool UseUnitForFuelCost { get; set; }
|
public bool UseUnitForFuelCost { get; set; }
|
||||||
public bool ShowCalendar { get; set; }
|
public bool ShowCalendar { get; set; }
|
||||||
|
public bool ShowVehicleThumbnail { get; set; }
|
||||||
public List<UserColumnPreference> UserColumnPreferences { get; set; } = new List<UserColumnPreference>();
|
public List<UserColumnPreference> UserColumnPreferences { get; set; } = new List<UserColumnPreference>();
|
||||||
public ReminderUrgencyConfig ReminderUrgencyConfig { get; set; } = new ReminderUrgencyConfig();
|
public ReminderUrgencyConfig ReminderUrgencyConfig { get; set; } = new ReminderUrgencyConfig();
|
||||||
public string UserNameHash { get; set; }
|
public string UserNameHash { get; set; }
|
||||||
|
|||||||
@@ -40,6 +40,20 @@
|
|||||||
No Params
|
No Params
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row api-method">
|
||||||
|
<div class="col-1">
|
||||||
|
<span class="badge bg-success">GET</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-5 copyable testable">
|
||||||
|
<code>/api/version</code>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
Returns current version of LubeLogger and checks for updates
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
CheckForUpdate(bool) - checks for update(optional)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row api-method">
|
<div class="row api-method">
|
||||||
<div class="col-1">
|
<div class="col-1">
|
||||||
<span class="badge bg-success">GET</span>
|
<span class="badge bg-success">GET</span>
|
||||||
|
|||||||
@@ -13,17 +13,21 @@
|
|||||||
emailServerIsSetup = false;
|
emailServerIsSetup = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@section Nav {
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row mt-2">
|
||||||
|
<div class="d-flex lubelogger-navbar">
|
||||||
|
<div class="me-2" style="cursor:pointer;" onclick="returnToGarage()">
|
||||||
|
<img src="@config.GetSmallLogoUrl()" class="lubelogger-logo" />
|
||||||
|
</div>
|
||||||
|
<span class="text-truncate lead">@translator.Translate(userLanguage, "Admin Panel")</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@model AdminViewModel
|
@model AdminViewModel
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row d-flex align-items-center justify-content-between justify-content-md-start">
|
|
||||||
<div class="col-2 col-md-1">
|
|
||||||
<a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-7 text-end text-md-start">
|
|
||||||
<span class="display-6">@translator.Translate(userLanguage, "Admin Panel")</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -56,23 +60,23 @@
|
|||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<span class="lead">@translator.Translate(userLanguage, "Tokens")</span>
|
<span class="lead">@translator.Translate(userLanguage, "Tokens")</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center ms-auto">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1">
|
||||||
|
<i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Generate")
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-primary btn-md mt-1 mb-1" @(emailServerIsSetup ? "" : "disabled") onclick="toggleAutoNotify(event)">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" @(emailServerIsSetup ? "checked" : "disabled")>
|
||||||
|
<label class="form-check-label" for="enableAutoNotify">@translator.Translate(userLanguage, "Notify")</label>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center ms-auto">
|
|
||||||
<div class="btn-group">
|
|
||||||
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1">
|
|
||||||
<i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Generate")
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-outline-primary btn-md mt-1 mb-1" @(emailServerIsSetup ? "" : "disabled") onclick="toggleAutoNotify(event)">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" @(emailServerIsSetup ? "checked" : "disabled")>
|
|
||||||
<label class="form-check-label" for="enableAutoNotify">@translator.Translate(userLanguage, "Notify")</label>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-close btn-md mt-1 mb-1 ms-2" onclick="hideTokenModal()" aria-label="Close"></button>
|
<button class="btn btn-close btn-md mt-1 mb-1 ms-2" onclick="hideTokenModal()" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
|
|||||||
@@ -16,6 +16,71 @@
|
|||||||
<script src="~/js/supplyrecord.js?v=@StaticHelper.VersionNumber"></script>
|
<script src="~/js/supplyrecord.js?v=@StaticHelper.VersionNumber"></script>
|
||||||
<script src="~/lib/drawdown/drawdown.js"></script>
|
<script src="~/lib/drawdown/drawdown.js"></script>
|
||||||
}
|
}
|
||||||
|
@section Nav {
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row mt-2">
|
||||||
|
<div class="d-flex lubelogger-navbar">
|
||||||
|
<div class="me-2" style="cursor:pointer;" onclick="returnToGarage()">
|
||||||
|
<img src="@config.GetSmallLogoUrl()" class="lubelogger-logo lubelogger-tab" />
|
||||||
|
<img src="@config.GetLogoUrl()" class="lubelogger-logo lubelogger-mobile-nav-show" />
|
||||||
|
</div>
|
||||||
|
<ul class="nav nav-tabs lubelogger-tab flex-grow-1" id="homeTab" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link resizable-nav-link @(Model == "garage" ? "active" : "")" oncontextmenu="sortGarage(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Garage")</span></button>
|
||||||
|
</li>
|
||||||
|
@if (config.GetServerEnableShopSupplies())
|
||||||
|
{
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link resizable-nav-link" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Supplies")</span></button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@if (userConfig.ShowCalendar)
|
||||||
|
{
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link resizable-nav-link" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-calendar-week"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Calendar")</span></button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
<li class="nav-item ms-auto" role="presentation">
|
||||||
|
<button class="nav-link resizable-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"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Settings")</span></button>
|
||||||
|
</li>
|
||||||
|
@if (User.IsInRole("CookieAuth") || User.IsInRole("APIAuth"))
|
||||||
|
{
|
||||||
|
<li class="nav-item dropdown" role="presentation">
|
||||||
|
<a class="nav-link resizable-nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><i class="bi bi-person"></i><span class="ms-2 d-sm-none d-md-inline">@User.Identity.Name</span></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
@if (User.IsInRole(nameof(UserData.IsAdmin)))
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage, "Admin Panel")</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item" onclick="showRootAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item" onclick="showAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>@translator.Translate(userLanguage, "Logout")</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
<div class="lubelogger-navbar-button">
|
||||||
|
<button type="button" class="btn btn-adaptive" onclick="showMobileNav()"><i class="bi bi-list lubelogger-menu-icon"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
||||||
<ul class="navbar-nav" id="homeTab" role="tablist">
|
<ul class="navbar-nav" id="homeTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
@@ -61,62 +126,6 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mt-2">
|
|
||||||
<div class="d-flex lubelogger-navbar">
|
|
||||||
<img src="@config.GetLogoUrl()" class="lubelogger-logo" />
|
|
||||||
<div class="lubelogger-navbar-button">
|
|
||||||
<button type="button" class="btn btn-adaptive" onclick="showMobileNav()"><i class="bi bi-list lubelogger-menu-icon"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<ul class="nav nav-tabs lubelogger-tab" id="homeTab" role="tablist">
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link resizable-nav-link @(Model == "garage" ? "active" : "")" oncontextmenu="sortGarage(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Garage")</span></button>
|
|
||||||
</li>
|
|
||||||
@if (config.GetServerEnableShopSupplies())
|
|
||||||
{
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link resizable-nav-link" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Supplies")</span></button>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
@if (userConfig.ShowCalendar){
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link resizable-nav-link" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-calendar-week"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Calendar")</span></button>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
<li class="nav-item ms-auto" role="presentation">
|
|
||||||
<button class="nav-link resizable-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"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Settings")</span></button>
|
|
||||||
</li>
|
|
||||||
@if (User.IsInRole("CookieAuth") || User.IsInRole("APIAuth"))
|
|
||||||
{
|
|
||||||
<li class="nav-item dropdown" role="presentation">
|
|
||||||
<a class="nav-link resizable-nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><i class="bi bi-person"></i><span class="ms-2 d-sm-none d-md-inline">@User.Identity.Name</span></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
@if (User.IsInRole(nameof(UserData.IsAdmin)))
|
|
||||||
{
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"Admin Panel")</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
|
||||||
{
|
|
||||||
<li>
|
|
||||||
<button class="dropdown-item" onclick="showRootAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button>
|
|
||||||
</li>
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
<li>
|
|
||||||
<button class="dropdown-item" onclick="showAccountInformationModal()"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</button>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
<li>
|
|
||||||
<button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>@translator.Translate(userLanguage,"Logout")</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
<div class="tab-content" id="homeTab">
|
<div class="tab-content" id="homeTab">
|
||||||
<div class="tab-pane fade @(Model == "garage" ? "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 id="garageContainer">
|
<div id="garageContainer">
|
||||||
|
|||||||
@@ -90,6 +90,10 @@
|
|||||||
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="showCalendar" checked="@Model.UserConfig.ShowCalendar">
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="showCalendar" checked="@Model.UserConfig.ShowCalendar">
|
||||||
<label class="form-check-label" for="showCalendar">@translator.Translate(userLanguage, "Show Calendar")</label>
|
<label class="form-check-label" for="showCalendar">@translator.Translate(userLanguage, "Show Calendar")</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check form-switch form-check-inline">
|
||||||
|
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="showVehicleThumbnail" checked="@Model.UserConfig.ShowVehicleThumbnail">
|
||||||
|
<label class="form-check-label" for="showCalendar">@translator.Translate(userLanguage, "Show Vehicle Thumbnail in Header")</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -161,6 +161,7 @@
|
|||||||
@await RenderSectionAsync("Scripts", required: false)
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@await RenderSectionAsync("Nav", required: false)
|
||||||
<div class="container" style="height:85vh;">
|
<div class="container" style="height:85vh;">
|
||||||
<main role="main">
|
<main role="main">
|
||||||
@RenderBody()
|
@RenderBody()
|
||||||
|
|||||||
@@ -25,6 +25,61 @@
|
|||||||
<script src="~/lib/chart-js/chart.umd.js"></script>
|
<script src="~/lib/chart-js/chart.umd.js"></script>
|
||||||
<script src="~/lib/drawdown/drawdown.js"></script>
|
<script src="~/lib/drawdown/drawdown.js"></script>
|
||||||
}
|
}
|
||||||
|
@section Nav{
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row mt-2">
|
||||||
|
<div class="d-flex lubelogger-navbar">
|
||||||
|
<div class="me-2" style="cursor:pointer;" onclick="returnToGarage()">
|
||||||
|
@if(userConfig.ShowVehicleThumbnail) {
|
||||||
|
<img src="@Model.ImageLocation" class="lubelogger-vehicle-logo @(string.IsNullOrWhiteSpace(Model.SoldDate) ? "" : "sold")" />
|
||||||
|
} else {
|
||||||
|
<img src="@config.GetSmallLogoUrl()" class="lubelogger-logo" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<ul class="nav nav-tabs lubelogger-tab flex-grow-1" id="vehicleTab" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.Dashboard)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-file-bar-graph"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Dashboard")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.PlanRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-bar-chart-steps"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Planner")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.OdometerRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-speedometer"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Odometer")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.ServiceRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><i class="bi bi-card-checklist"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Service Records")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.RepairRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.RepairRecord)" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-exclamation-octagon"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Repairs")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.UpgradeRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-wrench-adjustable"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Upgrades")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.GasRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.GasRecord)" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-fuel-pump"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Fuel")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.SupplyRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.SupplyRecord)" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Supplies")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.TaxRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.TaxRecord)" id="tax-tab" data-bs-toggle="tab" data-bs-target="#tax-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-currency-dollar"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Taxes")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.NoteRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.NoteRecord)" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-journal-bookmark"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Notes")</span></button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.ReminderRecord)">
|
||||||
|
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ReminderRecord)" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell"></i></div><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Reminders")</span></button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<span style="cursor:pointer;" onclick="editVehicle(@Model.Id)" class="text-truncate"><span class="lead">@($"{Model.Year} {Model.Make} {Model.Model}")<small class="text-body-secondary">@($"(#{StaticHelper.GetVehicleIdentifier(Model)})")</small></span><span class="ms-2 lubelogger-tab"><i class="bi bi-pencil-square"></i></span></span>
|
||||||
|
<div class="lubelogger-navbar-button">
|
||||||
|
<button type="button" class="btn btn-adaptive" onclick="showMobileNav()"><i class="bi bi-list lubelogger-menu-icon"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
||||||
<ul class="nav navbar-nav" id="vehicleTab" role="tablist">
|
<ul class="nav navbar-nav" id="vehicleTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation" style="order: -2">
|
<li class="nav-item" role="presentation" style="order: -2">
|
||||||
@@ -69,52 +124,6 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<button onclick="returnToGarage()" class="lubelogger-tab btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></button>
|
|
||||||
<h1 class="text-truncate display-4">@($"{Model.Year} {Model.Make} {Model.Model}")<small class="text-body-secondary">@($"(#{StaticHelper.GetVehicleIdentifier(Model)})")</small></h1>
|
|
||||||
<button onclick="editVehicle(@Model.Id)" class="lubelogger-tab btn btn-warning btn-md mt-1 mb-1"><i class="bi bi-pencil-square"></i></button>
|
|
||||||
<div class="lubelogger-navbar-button">
|
|
||||||
<button type="button" class="btn btn-adaptive" onclick="showMobileNav()"><i class="bi bi-list lubelogger-menu-icon"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<ul class="nav nav-tabs lubelogger-tab" id="vehicleTab" role="tablist">
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.Dashboard)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.Dashboard)" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-file-bar-graph"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Dashboard")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.PlanRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.PlanRecord)" id="plan-tab" data-bs-toggle="tab" data-bs-target="#plan-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-bar-chart-steps"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Planner")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.OdometerRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.OdometerRecord)" id="odometer-tab" data-bs-toggle="tab" data-bs-target="#odometer-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-speedometer"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Odometer")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.ServiceRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab" data-bs-toggle="tab" data-bs-target="#servicerecord-tab-pane" type="button" role="tab" aria-selected="true"><i class="bi bi-card-checklist"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Service Records")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.RepairRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.RepairRecord)" id="accident-tab" data-bs-toggle="tab" data-bs-target="#accident-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-exclamation-octagon"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Repairs")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.UpgradeRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.UpgradeRecord)" id="upgrade-tab" data-bs-toggle="tab" data-bs-target="#upgrade-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-wrench-adjustable"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Upgrades")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.GasRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.GasRecord)" id="gas-tab" data-bs-toggle="tab" data-bs-target="#gas-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-fuel-pump"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Fuel")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.SupplyRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.SupplyRecord)" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Supplies")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.TaxRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.TaxRecord)" id="tax-tab" data-bs-toggle="tab" data-bs-target="#tax-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-currency-dollar"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Taxes")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.NoteRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.NoteRecord)" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-journal-bookmark"></i><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Notes")</span></button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation" style="order: @userConfig.TabOrder.FindIndex(x=>x == ImportMode.ReminderRecord)">
|
|
||||||
<button class="nav-link resizable-nav-link @StaticHelper.DefaultActiveTab(userConfig, ImportMode.ReminderRecord)" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell"></i></div><span class="ms-2 d-sm-none d-md-inline">@translator.Translate(userLanguage, "Reminders")</span></button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="tab-content" id="vehicleTabContent">
|
<div class="tab-content" id="vehicleTabContent">
|
||||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab-pane" role="tabpanel" tabindex="0"></div>
|
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.ServiceRecord)" id="servicerecord-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||||
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.GasRecord)" id="gas-tab-pane" role="tabpanel" tabindex="0"></div>
|
<div class="tab-pane fade @StaticHelper.DefaultActiveTabContent(userConfig, ImportMode.GasRecord)" id="gas-tab-pane" role="tabpanel" tabindex="0"></div>
|
||||||
|
|||||||
@@ -6,10 +6,15 @@
|
|||||||
var barGraphColors = StaticHelper.GetBarChartColors();
|
var barGraphColors = StaticHelper.GetBarChartColors();
|
||||||
var userConfig = config.GetUserConfig(User);
|
var userConfig = config.GetUserConfig(User);
|
||||||
var userLanguage = userConfig.UserLanguage;
|
var userLanguage = userConfig.UserLanguage;
|
||||||
|
|
||||||
|
var graphGrace = Decimal.ToInt32(Model.CostData.Max(x => x.Cost) - Model.CostData.Min(x => x.Cost));
|
||||||
|
if (graphGrace < 0 || Model.CostData.Min(x=>x.Cost) - graphGrace < 0)
|
||||||
|
{
|
||||||
|
graphGrace = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@if (Model.CostData.Any(x => x.Cost > 0))
|
@if (Model.CostData.Any(x => x.Cost > 0))
|
||||||
{
|
{
|
||||||
|
|
||||||
<canvas id="bar-chart-mpg"></canvas>
|
<canvas id="bar-chart-mpg"></canvas>
|
||||||
<script>
|
<script>
|
||||||
renderChart();
|
renderChart();
|
||||||
@@ -54,7 +59,8 @@
|
|||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: false,
|
||||||
|
grace: decodeHTMLEntities('@(graphGrace)'),
|
||||||
ticks: {
|
ticks: {
|
||||||
color: useDarkMode ? "#fff" : "#000"
|
color: useDarkMode ? "#fff" : "#000"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,14 @@
|
|||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||||
<label for="serviceRecordFiles">@translator.Translate(userLanguage, "Upload more documents")</label>
|
<label for="noteFiles">@translator.Translate(userLanguage, "Upload more documents")</label>
|
||||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept="@config.GetAllowedFileUploadExtensions()" class="form-control-file" id="noteFiles">
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept="@config.GetAllowedFileUploadExtensions()" class="form-control-file" id="noteFiles">
|
||||||
<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
|
<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<label for="serviceRecordFiles">@translator.Translate(userLanguage, "Upload documents(optional)")</label>
|
<label for="noteFiles">@translator.Translate(userLanguage, "Upload documents(optional)")</label>
|
||||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept="@config.GetAllowedFileUploadExtensions()" class="form-control-file" id="noteFiles">
|
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept="@config.GetAllowedFileUploadExtensions()" class="form-control-file" id="noteFiles">
|
||||||
<br />
|
<br />
|
||||||
<small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
|
<small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
|
||||||
@@ -87,4 +87,4 @@
|
|||||||
function getNoteModelData(){
|
function getNoteModelData(){
|
||||||
return { id: @Model.Id}
|
return { id: @Model.Id}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
}
|
}
|
||||||
@model ReportViewModel
|
@model ReportViewModel
|
||||||
<div class="container reportTabContainer">
|
<div class="container reportTabContainer">
|
||||||
|
<div class="row hideOnPrint" id="reportHeaderContent">
|
||||||
|
@await Html.PartialAsync("_ReportHeader", Model.ReportHeaderForVehicle)
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
<div class="row hideOnPrint">
|
<div class="row hideOnPrint">
|
||||||
<div class="col-md-3 col-12 mt-2">
|
<div class="col-md-3 col-12 mt-2">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
24
Views/Vehicle/_ReportHeader.cshtml
Normal file
24
Views/Vehicle/_ReportHeader.cshtml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
@using CarCareTracker.Helper
|
||||||
|
@inject IConfigHelper config
|
||||||
|
@inject ITranslationHelper translator
|
||||||
|
@{
|
||||||
|
var userConfig = config.GetUserConfig(User);
|
||||||
|
var userLanguage = userConfig.UserLanguage;
|
||||||
|
}
|
||||||
|
@model ReportHeader
|
||||||
|
<div class="col-md-3 col-12 mt-2 text-center">
|
||||||
|
<span class="lead">@Model.MaxOdometer.ToString("N0")</span><br />
|
||||||
|
<span class="text-secondary">@translator.Translate(userLanguage, "Last Reported Odometer Reading")</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-12 mt-2 text-center">
|
||||||
|
<span class="lead">@Model.DistanceTraveled.ToString("N0")</span><br />
|
||||||
|
<span class="text-secondary">@translator.Translate(userLanguage, "Distance Traveled")</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-12 mt-2 text-center">
|
||||||
|
<span class="lead">@StaticHelper.HideZeroCost(Model.TotalCost.ToString("C2"), true)</span><br />
|
||||||
|
<span class="text-secondary">@translator.Translate(userLanguage, "Total Cost")</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-12 mt-2 text-center">
|
||||||
|
<span class="lead">@Model.AverageMPG</span><br />
|
||||||
|
<span class="text-secondary">@translator.Translate(userLanguage, "Average Fuel Economy")</span>
|
||||||
|
</div>
|
||||||
@@ -19,7 +19,8 @@
|
|||||||
"EnableAutoReminderRefresh": false,
|
"EnableAutoReminderRefresh": false,
|
||||||
"EnableAutoOdometerInsert": false,
|
"EnableAutoOdometerInsert": false,
|
||||||
"EnableShopSupplies": false,
|
"EnableShopSupplies": false,
|
||||||
"ShowCalendar": true,
|
"ShowCalendar": true,
|
||||||
|
"ShowVehicleThumbnail": true,
|
||||||
"EnableExtraFieldColumns": false,
|
"EnableExtraFieldColumns": false,
|
||||||
"UseUKMPG": false,
|
"UseUKMPG": false,
|
||||||
"UseThreeDecimalGasCost": true,
|
"UseThreeDecimalGasCost": true,
|
||||||
|
|||||||
@@ -242,6 +242,18 @@ html {
|
|||||||
background-color: #0d6efd;
|
background-color: #0d6efd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lubelogger-navbar {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lubelogger-tab {
|
||||||
|
border:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lubelogger-tab .nav-link {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
/*Media Queries*/
|
/*Media Queries*/
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
.lubelogger-tab {
|
.lubelogger-tab {
|
||||||
@@ -298,10 +310,6 @@ html {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lubelogger-navbar {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lubelogger-navbar-button {
|
.lubelogger-navbar-button {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -500,7 +508,8 @@ html[data-bs-theme="light"] .api-method:hover {
|
|||||||
|
|
||||||
.lubelogger-logo {
|
.lubelogger-logo {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
width: 204px;
|
min-width: 48px;
|
||||||
|
max-width: 204px;
|
||||||
object-fit: scale-down;
|
object-fit: scale-down;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -526,4 +535,16 @@ html[data-bs-theme="light"] .api-method:hover {
|
|||||||
font-size: 0.6em;
|
font-size: 0.6em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
top: 15%
|
top: 15%
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lubelogger-vehicle-logo {
|
||||||
|
height: 48px;
|
||||||
|
width: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lubelogger-vehicle-logo.sold {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
BIN
wwwroot/defaults/lubelogger_logo_small.png
Normal file
BIN
wwwroot/defaults/lubelogger_logo_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -143,6 +143,14 @@ function refreshMPGChart() {
|
|||||||
var year = getYear();
|
var year = getYear();
|
||||||
$.post('/Vehicle/GetMonthMPGByVehicle', {vehicleId: vehicleId, year: year}, function (data) {
|
$.post('/Vehicle/GetMonthMPGByVehicle', {vehicleId: vehicleId, year: year}, function (data) {
|
||||||
$("#monthFuelMileageReportContent").html(data);
|
$("#monthFuelMileageReportContent").html(data);
|
||||||
|
refreshReportHeader();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function refreshReportHeader() {
|
||||||
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
|
var year = getYear();
|
||||||
|
$.post('/Vehicle/GetSummaryForVehicle', { vehicleId: vehicleId, year: year }, function (data) {
|
||||||
|
$("#reportHeaderContent").html(data);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function setSelectedMetrics() {
|
function setSelectedMetrics() {
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ function updateSettings() {
|
|||||||
enableAutoOdometerInsert: $("#enableAutoOdometerInsert").is(":checked"),
|
enableAutoOdometerInsert: $("#enableAutoOdometerInsert").is(":checked"),
|
||||||
enableShopSupplies: $("#enableShopSupplies").is(":checked"),
|
enableShopSupplies: $("#enableShopSupplies").is(":checked"),
|
||||||
showCalendar: $("#showCalendar").is(":checked"),
|
showCalendar: $("#showCalendar").is(":checked"),
|
||||||
|
showVehicleThumbnail: $("#showVehicleThumbnail").is(":checked"),
|
||||||
enableExtraFieldColumns: $("#enableExtraFieldColumns").is(":checked"),
|
enableExtraFieldColumns: $("#enableExtraFieldColumns").is(":checked"),
|
||||||
hideSoldVehicles: $("#hideSoldVehicles").is(":checked"),
|
hideSoldVehicles: $("#hideSoldVehicles").is(":checked"),
|
||||||
preferredGasUnit: $("#preferredGasUnit").val(),
|
preferredGasUnit: $("#preferredGasUnit").val(),
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
function successToast(message) {
|
function returnToGarage() {
|
||||||
|
window.location.href = '/Home';
|
||||||
|
}
|
||||||
|
function successToast(message) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
toast: true,
|
toast: true,
|
||||||
position: "top-end",
|
position: "top-end",
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
function returnToGarage() {
|
$(document).ready(function () {
|
||||||
window.location.href = '/Home';
|
|
||||||
}
|
|
||||||
$(document).ready(function () {
|
|
||||||
var vehicleId = GetVehicleId().vehicleId;
|
var vehicleId = GetVehicleId().vehicleId;
|
||||||
//bind tabs
|
//bind tabs
|
||||||
$('button[data-bs-toggle="tab"]').on('show.bs.tab', function (e) {
|
$('button[data-bs-toggle="tab"]').on('show.bs.tab', function (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user