Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cf733b9c6 | ||
|
|
1eb6e2cedf | ||
|
|
ef4deaba8f | ||
|
|
e8c196c2fa | ||
|
|
f7c9db6353 | ||
|
|
4ce720ff97 | ||
|
|
a96011629b | ||
|
|
9dcdcf97e8 | ||
|
|
5148338f52 | ||
|
|
0d3c04d8f8 | ||
|
|
15328a14b4 | ||
|
|
2d092f722a | ||
|
|
8825cb9b9b | ||
|
|
2f17e303ab | ||
|
|
4b56c8a343 | ||
|
|
7b6b62c623 | ||
|
|
07f5e66491 | ||
|
|
fe633f3220 | ||
|
|
af1090553f | ||
|
|
92c2e66660 | ||
|
|
08372f9dcb | ||
|
|
64ea0e2eee | ||
|
|
7ab476a88f | ||
|
|
de41ca911d | ||
|
|
dde9688f96 | ||
|
|
c1ca63edc0 | ||
|
|
cbc430499f | ||
|
|
4da9fa4802 | ||
|
|
42586d9556 | ||
|
|
ea4387d4ab | ||
|
|
61c2600286 | ||
|
|
163a33ae3a | ||
|
|
37d064aa62 |
1
.env
1
.env
@@ -2,7 +2,6 @@ LC_ALL=en_US.UTF-8
|
||||
LANG=en_US.UTF-8
|
||||
MailConfig__EmailServer=""
|
||||
MailConfig__EmailFrom=""
|
||||
MailConfig__UseSSL="false"
|
||||
MailConfig__Port=587
|
||||
MailConfig__Username=""
|
||||
MailConfig__Password=""
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="MailKit" Version="4.5.0" />
|
||||
<PackageReference Include="Npgsql" Version="8.0.2" />
|
||||
<PackageReference Include="Npgsql" Version="8.0.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -219,6 +219,13 @@ namespace CarCareTracker.Controllers
|
||||
var userName = User.Identity.Name;
|
||||
return PartialView("_AccountModal", new UserData() { EmailAddress = emailAddress, UserName = userName });
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public IActionResult GetRootAccountInformationModal()
|
||||
{
|
||||
var userName = User.Identity.Name;
|
||||
return PartialView("_RootAccountModal", new UserData() { UserName = userName });
|
||||
}
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
|
||||
@@ -220,7 +220,7 @@ namespace CarCareTracker.Controllers
|
||||
var result = _loginLogic.ResetPasswordByUser(credentials);
|
||||
return Json(result);
|
||||
}
|
||||
[Authorize] //User must already be logged in to do this.
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))] //User must already be logged in as root user to do this.
|
||||
[HttpPost]
|
||||
public IActionResult CreateLoginCreds(LoginModel credentials)
|
||||
{
|
||||
@@ -235,7 +235,7 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
return Json(false);
|
||||
}
|
||||
[Authorize]
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public IActionResult DestroyLoginCreds()
|
||||
{
|
||||
|
||||
@@ -439,7 +439,8 @@ namespace CarCareTracker.Controllers
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any),
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
if (string.IsNullOrWhiteSpace(importModel.Cost) && !string.IsNullOrWhiteSpace(importModel.Price))
|
||||
{
|
||||
@@ -495,7 +496,8 @@ namespace CarCareTracker.Controllers
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {importModel.Date}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
@@ -518,7 +520,8 @@ namespace CarCareTracker.Controllers
|
||||
InitialMileage = string.IsNullOrWhiteSpace(importModel.InitialOdometer) ? 0 : decimal.ToInt32(decimal.Parse(importModel.InitialOdometer, NumberStyles.Any)),
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord);
|
||||
}
|
||||
@@ -537,7 +540,8 @@ namespace CarCareTracker.Controllers
|
||||
Priority = parsedPriority,
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Plan Record on {importModel.DateCreated}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_planRecordDataAccess.SavePlanRecordToVehicle(convertedRecord);
|
||||
}
|
||||
@@ -551,7 +555,8 @@ namespace CarCareTracker.Controllers
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {importModel.Date}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
@@ -575,7 +580,8 @@ namespace CarCareTracker.Controllers
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Upgrade Record on {importModel.Date}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
@@ -601,7 +607,8 @@ namespace CarCareTracker.Controllers
|
||||
Description = importModel.Description,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Notes = importModel.Notes,
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(convertedRecord);
|
||||
}
|
||||
@@ -614,7 +621,8 @@ namespace CarCareTracker.Controllers
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Tax Record on {importModel.Date}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
|
||||
}
|
||||
|
||||
@@ -146,7 +146,11 @@ namespace CarCareTracker.Helper
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect(server, mailConfig.Port, MailKit.Security.SecureSocketOptions.Auto);
|
||||
client.Authenticate(mailConfig.Username, mailConfig.Password);
|
||||
//perform authentication if either username or password is provided.
|
||||
//do not perform authentication if neither are provided.
|
||||
if (!string.IsNullOrWhiteSpace(mailConfig.Username) || !string.IsNullOrWhiteSpace(mailConfig.Password)) {
|
||||
client.Authenticate(mailConfig.Username, mailConfig.Password);
|
||||
}
|
||||
try
|
||||
{
|
||||
client.Send(message);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace CarCareTracker.Helper
|
||||
/// </summary>
|
||||
public static class StaticHelper
|
||||
{
|
||||
public static string VersionNumber = "1.3.3";
|
||||
public static string VersionNumber = "1.3.5";
|
||||
public static string DbName = "data/cartracker.db";
|
||||
public static string UserConfigPath = "config/userConfig.json";
|
||||
public static string GenericErrorMessage = "An error occurred, please try again later";
|
||||
|
||||
@@ -27,6 +27,18 @@ namespace CarCareTracker.MapProfile
|
||||
Map(m => m.Type).Name(["type"]);
|
||||
Map(m => m.Priority).Name(["priority"]);
|
||||
Map(m => m.Tags).Name(["tags"]);
|
||||
Map(m => m.ExtraFields).Convert(row =>
|
||||
{
|
||||
var attributes = new Dictionary<string, string>();
|
||||
foreach (var header in row.Row.HeaderRecord)
|
||||
{
|
||||
if (header.ToLower().StartsWith("extrafield_"))
|
||||
{
|
||||
attributes.Add(header.Substring(11), row.Row.GetField(header));
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
{
|
||||
public string EmailServer { get; set; }
|
||||
public string EmailFrom { get; set; }
|
||||
public bool UseSSL { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
public string PartSupplier { get; set; }
|
||||
public string PartQuantity { get; set; }
|
||||
public string Tags { get; set; }
|
||||
public Dictionary<string,string> ExtraFields {get;set;}
|
||||
}
|
||||
|
||||
public class SupplyRecordExportModel
|
||||
|
||||
@@ -41,7 +41,12 @@
|
||||
<a class="dropdown-item" href="/Admin"><span class="display-3 ms-2"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"Admin Panel")</span></a>
|
||||
</li>
|
||||
}
|
||||
@if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
<li>
|
||||
<button class="nav-link" onclick="showRootAccountInformationModal()"><span class="display-3 ms-2"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</span></button>
|
||||
</li>
|
||||
} else
|
||||
{
|
||||
<li>
|
||||
<button class="nav-link" onclick="showAccountInformationModal()"><span class="display-3 ms-2"><i class="bi bi-person-gear me-2"></i>@translator.Translate(userLanguage, "Profile")</span></button>
|
||||
@@ -90,7 +95,12 @@
|
||||
<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)))
|
||||
@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>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
var userLanguage = userConfig.UserLanguage;
|
||||
}
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addVehicleModalLabel">@translator.Translate(userLanguage, "Update Profile")</h5>
|
||||
<h5 class="modal-title" id="updateAccountModalLabel">@translator.Translate(userLanguage, "Update Profile")</h5>
|
||||
<button type="button" class="btn-close" onclick="hideAccountInformationModal()" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
26
Views/Home/_RootAccountModal.cshtml
Normal file
26
Views/Home/_RootAccountModal.cshtml
Normal file
@@ -0,0 +1,26 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@model UserData
|
||||
@{
|
||||
var userConfig = config.GetUserConfig(User);
|
||||
var userLanguage = userConfig.UserLanguage;
|
||||
}
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="updateRootAccountModalLabel">@translator.Translate(userLanguage, "Update Profile")</h5>
|
||||
<button type="button" class="btn-close" onclick="hideAccountInformationModal()" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<label for="inputUsername">@translator.Translate(userLanguage, "Username")</label>
|
||||
<input type="text" id="inputUsername" class="form-control" placeholder="@translator.Translate(userLanguage, "Account Username")" value="@Model.UserName">
|
||||
<label for="inputPassword">@translator.Translate(userLanguage, "Password")</label>
|
||||
<input type="password" id="inputPassword" class="form-control" placeholder="@translator.Translate(userLanguage, "Password")" value="">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAccountInformationModal()">@translator.Translate(userLanguage, "Cancel")</button>
|
||||
<button type="button" onclick="validateAndSaveRootUserAccount()" class="btn btn-primary">@translator.Translate(userLanguage, "Update")</button>
|
||||
</div>
|
||||
@@ -70,8 +70,8 @@
|
||||
}
|
||||
function globalParseFloat(input){
|
||||
//remove thousands separator.
|
||||
var thousandSeparator = "@numberFormat.NumberGroupSeparator";
|
||||
var decimalSeparator = "@numberFormat.NumberDecimalSeparator";
|
||||
var thousandSeparator = decodeHTMLEntities("@numberFormat.NumberGroupSeparator");
|
||||
var decimalSeparator = decodeHTMLEntities("@numberFormat.NumberDecimalSeparator");
|
||||
var currencySymbol = decodeHTMLEntities("@numberFormat.CurrencySymbol");
|
||||
if (input == "---") {
|
||||
input = "0";
|
||||
@@ -85,13 +85,32 @@
|
||||
return parseFloat(input);
|
||||
}
|
||||
function globalFloatToString(input) {
|
||||
var decimalSeparator = "@numberFormat.NumberDecimalSeparator";
|
||||
var decimalSeparator = decodeHTMLEntities("@numberFormat.NumberDecimalSeparator");
|
||||
input = input.replace(".", decimalSeparator);
|
||||
return input;
|
||||
}
|
||||
function genericErrorMessage(){
|
||||
return decodeHTMLEntities('@translator.Translate(userLanguage, "An error has occurred, please try again later")');
|
||||
}
|
||||
function globalAppendCurrency(input){
|
||||
//check currency symbol position
|
||||
var currencySymbolPosition = "@numberFormat.CurrencyPositivePattern";
|
||||
var currencySymbol = decodeHTMLEntities("@numberFormat.CurrencySymbol");
|
||||
switch (currencySymbolPosition) {
|
||||
case "0":
|
||||
return `${currencySymbol}${input}`;
|
||||
break;
|
||||
case "1":
|
||||
return `${input}${currencySymbol}`;
|
||||
break;
|
||||
case "2":
|
||||
return `${currencySymbol} ${input}`;
|
||||
break;
|
||||
case "3":
|
||||
return `${input} ${currencySymbol}`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</head>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
@if (isNew)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('collisionRecordMileage')">+</button>
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('collisionRecordMileage')"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -17,23 +17,23 @@
|
||||
consumptionUnit = "kWh";
|
||||
} else if (useUKMPG)
|
||||
{
|
||||
consumptionUnit = "liters";
|
||||
consumptionUnit = @translator.Translate(userLanguage, "liters");
|
||||
}
|
||||
else
|
||||
{
|
||||
consumptionUnit = useMPG ? "gallons" : "liters";
|
||||
consumptionUnit = useMPG ? @translator.Translate(userLanguage, "gallons") : @translator.Translate(userLanguage, "liters");
|
||||
}
|
||||
if (useHours)
|
||||
{
|
||||
distanceUnit = "hours";
|
||||
distanceUnit = @translator.Translate(userLanguage, "hours");
|
||||
}
|
||||
else if (useUKMPG)
|
||||
{
|
||||
distanceUnit = "miles";
|
||||
distanceUnit = @translator.Translate(userLanguage, "miles");
|
||||
}
|
||||
else
|
||||
{
|
||||
distanceUnit = useMPG ? "miles" : "kilometers";
|
||||
distanceUnit = useMPG ? @translator.Translate(userLanguage, "miles") : @translator.Translate(userLanguage, "kilometers");
|
||||
}
|
||||
}
|
||||
<div class="modal-header">
|
||||
@@ -57,7 +57,7 @@
|
||||
@if (isNew)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('gasRecordMileage')">+</button>
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('gasRecordMileage')"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -23,14 +23,22 @@
|
||||
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||
</div>
|
||||
<label for="initialOdometerRecordMileage">@translator.Translate(userLanguage, "Initial Odometer")</label>
|
||||
<input type="number" inputmode="numeric" id="initialOdometerRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Initial Odometer reading")" value="@(Model.InitialMileage)">
|
||||
<div class="input-group">
|
||||
<input type="number" inputmode="numeric" id="initialOdometerRecordMileage" @(Model.InitialMileage != default ? "disabled" : "") class="form-control" placeholder="@translator.Translate(userLanguage,"Initial Odometer reading")" value="@(Model.InitialMileage)">
|
||||
@if (Model.InitialMileage != default)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-secondary zero-y-padding" onclick="toggleInitialOdometerEnabled()"><i class="bi bi-pencil"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<label for="odometerRecordMileage">@translator.Translate(userLanguage,"Odometer")</label>
|
||||
<div class="input-group">
|
||||
<input type="number" inputmode="numeric" id="odometerRecordMileage" class="form-control" placeholder="@translator.Translate(userLanguage,"Odometer reading")" value="@(isNew ? "" : Model.Mileage)">
|
||||
@if (isNew)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('odometerRecordMileage')">+</button>
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('odometerRecordMileage')"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<input type="text" id="reminderDescription" class="form-control" placeholder="@translator.Translate(userLanguage,"Reminder Description")" value="@Model.Description">
|
||||
<label>@translator.Translate(userLanguage,"Remind me on")</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricDate" value="@(ReminderMetric.Date)" checked="@(Model.Metric == ReminderMetric.Date)">
|
||||
<input class="form-check-input" onclick="enableRecurring()" type="radio" name="reminderMetricOptions" id="reminderMetricDate" value="@(ReminderMetric.Date)" checked="@(Model.Metric == ReminderMetric.Date)">
|
||||
<label class="form-check-label" for="reminderMetricDate">@translator.Translate(userLanguage,"Date")</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
@@ -29,7 +29,7 @@
|
||||
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricOdometer" value="@(ReminderMetric.Odometer)" checked="@(Model.Metric == ReminderMetric.Odometer)">
|
||||
<input class="form-check-input" onclick="enableRecurring()" type="radio" name="reminderMetricOptions" id="reminderMetricOdometer" value="@(ReminderMetric.Odometer)" checked="@(Model.Metric == ReminderMetric.Odometer)">
|
||||
<label class="form-check-label" for="reminderMetricOdometer">@translator.Translate(userLanguage,"Odometer")</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
@@ -37,12 +37,12 @@
|
||||
@if (isNew)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('reminderMileage')">+</button>
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('reminderMileage')"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricBoth" value="@(ReminderMetric.Both)" checked="@(Model.Metric == ReminderMetric.Both)">
|
||||
<input class="form-check-input" onclick="enableRecurring()" type="radio" name="reminderMetricOptions" id="reminderMetricBoth" value="@(ReminderMetric.Both)" checked="@(Model.Metric == ReminderMetric.Both)">
|
||||
<label class="form-check-label" for="reminderMetricBoth">@translator.Translate(userLanguage,"Whichever comes first")</label>
|
||||
</div>
|
||||
<div class="d-grid"></div>
|
||||
@@ -62,7 +62,7 @@
|
||||
<label class="form-check-label" for="reminderIsRecurring">@translator.Translate(userLanguage,"Is Recurring")</label>
|
||||
</div>
|
||||
<label for="reminderRecurringMileage">@translator.Translate(userLanguage,"Odometer")</label>
|
||||
<select class="form-select" onchange="checkCustomMileageInterval()" id="reminderRecurringMileage" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<select class="form-select" onchange="checkCustomMileageInterval()" id="reminderRecurringMileage" @(Model.IsRecurring && (Model.Metric == ReminderMetric.Odometer || Model.Metric == ReminderMetric.Both) ? "" : "disabled")>
|
||||
<!option value="Other" @(Model.ReminderMileageInterval == ReminderMileageInterval.Other ? "selected" : "")>@(Model.ReminderMileageInterval == ReminderMileageInterval.Other && Model.CustomMileageInterval > 0 ? $"{translator.Translate(userLanguage, "Other")}: {Model.CustomMileageInterval}" : $"{translator.Translate(userLanguage, "Other")}") </!option>
|
||||
<!option value="FiftyMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.FiftyMiles ? "selected" : "")>50 mi. / Km</!option>
|
||||
<!option value="OneHundredMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.OneHundredMiles ? "selected" : "")>100 mi. / Km</!option>
|
||||
@@ -83,7 +83,7 @@
|
||||
<!option value="OneHundredFiftyThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.OneHundredFiftyThousandMiles ? "selected" : "")>150000 mi. / Km</!option>
|
||||
</select>
|
||||
<label for="reminderRecurringMonth">Month</label>
|
||||
<select class="form-select" onchange="checkCustomMonthInterval()" id="reminderRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<select class="form-select" onchange="checkCustomMonthInterval()" id="reminderRecurringMonth" @(Model.IsRecurring && (Model.Metric == ReminderMetric.Date || Model.Metric == ReminderMetric.Both) ? "" : "disabled")>
|
||||
<!option value="Other" @(Model.ReminderMonthInterval == ReminderMonthInterval.Other ? "selected" : "")>@(Model.ReminderMonthInterval == ReminderMonthInterval.Other && Model.CustomMonthInterval > 0 ? $"{translator.Translate(userLanguage, "Other")}: {Model.CustomMonthInterval}" : $"{translator.Translate(userLanguage, "Other")}") </!option>
|
||||
<!option value="OneMonth" @(Model.ReminderMonthInterval == ReminderMonthInterval.OneMonth ? "selected" : "")>@translator.Translate(userLanguage, "1 Month")</!option>
|
||||
<!option value="ThreeMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>@translator.Translate(userLanguage,"3 Months")</!option>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<select class="form-select" id="yearOption" onchange="yearUpdated()">
|
||||
<option value="0">All Time</option>
|
||||
<option value="0">@translator.Translate(userLanguage, "All Time")</option>
|
||||
@foreach (int year in Model.Years)
|
||||
{
|
||||
<option value="@year">@year</option>
|
||||
@@ -32,7 +32,7 @@
|
||||
<div class="col-12 col-md-10">
|
||||
<div class="dropdown d-grid dropdown-center">
|
||||
<button class="btn btn-outline-warning dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
|
||||
Metrics
|
||||
@translator.Translate(userLanguage, "Metrics")
|
||||
</button>
|
||||
<ul class="dropdown-menu" style="width:100%;">
|
||||
<li class="dropdown-item">
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
@if (isNew)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('serviceRecordMileage')">+</button>
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('serviceRecordMileage')"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="input-group">
|
||||
<input type="text" inputmode="decimal" id="supplyRecordQuantity" class="form-control" placeholder="@translator.Translate(userLanguage,"Quantity")" value="@(isNew ? "1" : Model.Quantity)">
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm zero-y-padding btn-primary" onclick="replenishSupplies()">+</button>
|
||||
<button type="button" class="btn btn-sm zero-y-padding btn-primary" onclick="replenishSupplies()"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
var inStockQuantity = globalParseFloat(inStock.text());
|
||||
var unitPrice = globalParseFloat(priceField.text());
|
||||
//validation
|
||||
if (isNaN(requestedQuantity) || requestedQuantity > inStockQuantity) {
|
||||
if (isNaN(requestedQuantity) || requestedQuantity > inStockQuantity || requestedQuantity <= 0) {
|
||||
textField.addClass("is-invalid");
|
||||
hasError = true;
|
||||
} else {
|
||||
@@ -131,7 +131,7 @@
|
||||
var parsedFloat = globalFloatToString(totalSum);
|
||||
$("#supplySumLabel").text(`Total: ${parsedFloat}`);
|
||||
}
|
||||
$("#selectSuppliesButton").attr('disabled', (hasError || totalSum == 0));
|
||||
$("#selectSuppliesButton").attr('disabled', (hasError || selectedSupplies.toArray().length == 0));
|
||||
if (!hasError) {
|
||||
return {
|
||||
totalSum: globalFloatToString(totalSum),
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
@if (isNew)
|
||||
{
|
||||
<div class="input-group-text">
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('upgradeRecordMileage')">+</button>
|
||||
<button type="button" class="btn btn-sm btn-primary zero-y-padding" onclick="getLastOdometerReadingAndIncrement('upgradeRecordMileage')"><i class="bi bi-plus"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,7 @@ services:
|
||||
POSTGRES_PASSWORD: "lubepass"
|
||||
POSTGRES_DB: "lubelogger"
|
||||
volumes:
|
||||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
- postgres:/var/lib/postgresql/data
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
|
||||
6
init.sql
Normal file
6
init.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'app') THEN
|
||||
CREATE SCHEMA app;
|
||||
END IF;
|
||||
END $$;
|
||||
File diff suppressed because one or more lines are too long
BIN
wwwroot/defaults/lubelogger_maskable_icon_128.png
Normal file
BIN
wwwroot/defaults/lubelogger_maskable_icon_128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
BIN
wwwroot/defaults/lubelogger_maskable_icon_192.png
Normal file
BIN
wwwroot/defaults/lubelogger_maskable_icon_192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
wwwroot/defaults/lubelogger_maskable_icon_72.png
Normal file
BIN
wwwroot/defaults/lubelogger_maskable_icon_72.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -341,6 +341,47 @@ function showAccountInformationModal() {
|
||||
$('#accountInformationModal').modal('show');
|
||||
})
|
||||
}
|
||||
|
||||
function showRootAccountInformationModal() {
|
||||
$.get('/Home/GetRootAccountInformationModal', function (data) {
|
||||
$('#accountInformationModalContent').html(data);
|
||||
$('#accountInformationModal').modal('show');
|
||||
})
|
||||
}
|
||||
function validateAndSaveRootUserAccount() {
|
||||
var hasError = false;
|
||||
if ($('#inputUsername').val().trim() == '') {
|
||||
$('#inputUsername').addClass("is-invalid");
|
||||
hasError = true;
|
||||
} else {
|
||||
$('#inputUsername').removeClass("is-invalid");
|
||||
}
|
||||
if ($('#inputPassword').val().trim() == '') {
|
||||
$('#inputPassword').addClass("is-invalid");
|
||||
hasError = true;
|
||||
} else {
|
||||
$('#inputPassword').removeClass("is-invalid");
|
||||
}
|
||||
if (hasError) {
|
||||
errorToast("Please check the form data");
|
||||
return;
|
||||
}
|
||||
var userAccountInfo = {
|
||||
userName: $('#inputUsername').val(),
|
||||
password: $('#inputPassword').val()
|
||||
}
|
||||
$.post('/Login/CreateLoginCreds', { credentials: userAccountInfo }, function (data) {
|
||||
if (data) {
|
||||
//hide modal
|
||||
hideAccountInformationModal();
|
||||
successToast('Root Account Updated');
|
||||
performLogOut();
|
||||
} else {
|
||||
errorToast(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function hideAccountInformationModal() {
|
||||
$('#accountInformationModal').modal('hide');
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) / 3.785;
|
||||
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
|
||||
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`;
|
||||
elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
|
||||
});
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
@@ -196,7 +196,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) * 1.201;
|
||||
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
|
||||
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`;
|
||||
elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
|
||||
});
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
@@ -213,7 +213,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) * 3.785;
|
||||
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
|
||||
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`;
|
||||
elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
|
||||
});
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
@@ -227,7 +227,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) * 4.546;
|
||||
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
|
||||
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`;
|
||||
elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
|
||||
});
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
@@ -244,7 +244,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) / 1.201;
|
||||
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
|
||||
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`;
|
||||
elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
|
||||
});
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
@@ -258,7 +258,7 @@ function convertGasConsumptionUnits(currentUnit, destinationUnit, save) {
|
||||
$("[data-gas-type='unitcost']").map((index, elem) => {
|
||||
var convertedAmount = globalParseFloat(elem.innerText) / 4.546;
|
||||
var decimalPoints = getGlobalConfig().useThreeDecimals ? 3 : 2;
|
||||
elem.innerText = `${getGlobalConfig().currencySymbol}${globalFloatToString(convertedAmount.toFixed(decimalPoints))}`;
|
||||
elem.innerText = `${globalAppendCurrency(globalFloatToString(convertedAmount.toFixed(decimalPoints)))}`;
|
||||
});
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
|
||||
@@ -209,3 +209,11 @@ function saveMultipleOdometerRecordsToVehicle() {
|
||||
}
|
||||
})
|
||||
}
|
||||
function toggleInitialOdometerEnabled() {
|
||||
if ($("#initialOdometerRecordMileage").prop("disabled")) {
|
||||
$("#initialOdometerRecordMileage").prop("disabled", false);
|
||||
} else {
|
||||
$("#initialOdometerRecordMileage").prop("disabled", true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -137,8 +137,20 @@ function appendMileageToOdometer(increment) {
|
||||
function enableRecurring() {
|
||||
var reminderIsRecurring = $("#reminderIsRecurring").is(":checked");
|
||||
if (reminderIsRecurring) {
|
||||
$("#reminderRecurringMileage").attr('disabled', false);
|
||||
$("#reminderRecurringMonth").attr('disabled', false);
|
||||
//check selected metric
|
||||
var reminderMetric = $('#reminderOptions input:radio:checked').val();
|
||||
if (reminderMetric == "Date") {
|
||||
$("#reminderRecurringMonth").attr('disabled', false);
|
||||
$("#reminderRecurringMileage").attr('disabled', true);
|
||||
}
|
||||
else if (reminderMetric == "Odometer") {
|
||||
$("#reminderRecurringMileage").attr('disabled', false);
|
||||
$("#reminderRecurringMonth").attr('disabled', true);
|
||||
}
|
||||
else if (reminderMetric == "Both") {
|
||||
$("#reminderRecurringMonth").attr('disabled', false);
|
||||
$("#reminderRecurringMileage").attr('disabled', false);
|
||||
}
|
||||
} else {
|
||||
$("#reminderRecurringMileage").attr('disabled', true);
|
||||
$("#reminderRecurringMonth").attr('disabled', true);
|
||||
|
||||
@@ -178,8 +178,8 @@ function uploadFileAsync(event) {
|
||||
});
|
||||
}
|
||||
function isValidMoney(input) {
|
||||
const euRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}(\.?\d{3})?(,\d{1,3}?)?\)?$/;
|
||||
const usRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}(,?\d{3})?(\.\d{1,3}?)?\)?$/;
|
||||
const euRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}((\.\d{3}){0,8}|(\d{3}){0,8})(,\d{1,3}?)?\)?$/;
|
||||
const usRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}((,\d{3}){0,8}|(\d{3}){0,8})(\.\d{1,3}?)?\)?$/;
|
||||
return (euRegex.test(input) || usRegex.test(input));
|
||||
}
|
||||
function initDatePicker(input, futureOnly) {
|
||||
@@ -339,7 +339,7 @@ function updateAggregateLabels() {
|
||||
if (labelsToSum.length > 0) {
|
||||
newSum = labelsToSum.map(x => globalParseFloat(x.textContent)).reduce((a, b,) => a + b).toFixed(2);
|
||||
}
|
||||
sumLabel.text(`${sumLabel.text().split(':')[0]}: ${getGlobalConfig().currencySymbol}${newSum}`)
|
||||
sumLabel.text(`${sumLabel.text().split(':')[0]}: ${globalAppendCurrency(globalFloatToString(newSum))}`)
|
||||
}
|
||||
//Sum Distance
|
||||
var sumDistanceLabel = $("[data-aggregate-type='sum-distance']");
|
||||
|
||||
@@ -480,9 +480,9 @@ function getRecordsDeltaStats(recordIds) {
|
||||
var diffOdo = maxOdo - minOdo;
|
||||
var diffDate = maxDate - minDate;
|
||||
var divisibleCount = recordIds.length - 1;
|
||||
var averageOdo = diffOdo > 0 ? (diffOdo / divisibleCount).toFixed(2) : 0;
|
||||
var averageDays = diffDate > 0 ? Math.floor((diffDate / divisibleCount) / 8.64e7) : 0;
|
||||
var averageSum = costSum > 0 ? (costSum / recordIds.length).toFixed(2) : 0;
|
||||
var averageOdo = diffOdo > 0 ? (diffOdo / divisibleCount).toFixed(2) : '0';
|
||||
var averageDays = diffDate > 0 ? Math.floor((diffDate / divisibleCount) / 8.64e7) : '0';
|
||||
var averageSum = costSum > 0 ? (costSum / recordIds.length).toFixed(2) : '0';
|
||||
costSum = costSum.toFixed(2);
|
||||
Swal.fire({
|
||||
title: "Record Statistics",
|
||||
@@ -490,9 +490,9 @@ function getRecordsDeltaStats(recordIds) {
|
||||
<br />
|
||||
<p>Average Days between Records: ${averageDays}</p>
|
||||
<br />
|
||||
<p>Total Cost: ${getGlobalConfig().currencySymbol} ${globalFloatToString(costSum)}</p>
|
||||
<p>Total Cost: ${globalAppendCurrency(globalFloatToString(costSum))}</p>
|
||||
<br />
|
||||
<p>Average Cost: ${getGlobalConfig().currencySymbol} ${globalFloatToString(averageSum)}</p>`
|
||||
<p>Average Cost: ${globalAppendCurrency(globalFloatToString(averageSum))}</p>`
|
||||
,
|
||||
icon: "info"
|
||||
});
|
||||
|
||||
@@ -6,22 +6,44 @@
|
||||
{
|
||||
"src": "/defaults/lubelogger_icon_72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/defaults/lubelogger_maskable_icon_72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/defaults/lubelogger_icon_128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/defaults/lubelogger_maskable_icon_128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/defaults/lubelogger_icon_144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/defaults/lubelogger_icon_192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/defaults/lubelogger_maskable_icon_192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
|
||||
Reference in New Issue
Block a user