From b06ad0cdaa18219942f1192dee0bca8c8349c640 Mon Sep 17 00:00:00 2001 From: "DESKTOP-T0O5CDB\\DESK-555BD" Date: Fri, 1 Nov 2024 16:59:10 -0600 Subject: [PATCH] bump version and kiosk enhancement. --- Controllers/HomeController.cs | 57 ++++++++++++------- Enum/KioskMode.cs | 10 ++++ Helper/StaticHelper.cs | 46 ++++++++++++++++ Logic/VehicleLogic.cs | 41 ++++++++++++++ Models/Kiosk/KioskViewModel.cs | 14 +++++ README.md | 1 + Views/API/Index.cshtml | 6 ++ Views/Home/Kiosk.cshtml | 88 +++++++++++++++++++++++++++--- Views/Home/_Kiosk.cshtml | 24 +++++--- Views/Home/_KioskPlan.cshtml | 86 +++++++++++++++++++++++++++++ Views/Home/_KioskReminder.cshtml | 47 ++++++++++++++++ Views/Home/_Settings.cshtml | 1 + wwwroot/defaults/en_US.json | 2 +- wwwroot/lib/masonry/masonry.min.js | 9 +++ 14 files changed, 397 insertions(+), 35 deletions(-) create mode 100644 Enum/KioskMode.cs create mode 100644 Models/Kiosk/KioskViewModel.cs create mode 100644 Views/Home/_KioskPlan.cshtml create mode 100644 Views/Home/_KioskReminder.cshtml create mode 100644 wwwroot/lib/masonry/masonry.min.js diff --git a/Controllers/HomeController.cs b/Controllers/HomeController.cs index d5bf7c5..f7edae9 100644 --- a/Controllers/HomeController.cs +++ b/Controllers/HomeController.cs @@ -55,25 +55,56 @@ namespace CarCareTracker.Controllers { return View(model: tab); } - public IActionResult Kiosk(string exceptions) + [Route("/kiosk")] + public IActionResult Kiosk(string exclusions, KioskMode kioskMode = KioskMode.Vehicle) { try { - var exceptionList = string.IsNullOrWhiteSpace(exceptions) ? new List() : exceptions.Split(',').Select(x => int.Parse(x)).ToList(); - return View(exceptionList); + var viewModel = new KioskViewModel + { + Exclusions = string.IsNullOrWhiteSpace(exclusions) ? new List() : exclusions.Split(',').Select(x => int.Parse(x)).ToList(), + KioskMode = kioskMode + }; + return View(viewModel); } catch (Exception ex) { - return View(new List()); + _logger.LogError(ex.Message); + return View(new KioskViewModel()); } } - public IActionResult KioskContent(List exceptionList) + [HttpPost] + public IActionResult KioskContent(KioskViewModel kioskParameters) { var vehiclesStored = _dataAccess.GetVehicles(); if (!User.IsInRole(nameof(UserData.IsRootUser))) { vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID()); } - vehiclesStored.RemoveAll(x => exceptionList.Contains(x.Id)); + vehiclesStored.RemoveAll(x => kioskParameters.Exclusions.Contains(x.Id)); + var userConfig = _config.GetUserConfig(User); + if (userConfig.HideSoldVehicles) + { + vehiclesStored.RemoveAll(x => !string.IsNullOrWhiteSpace(x.SoldDate)); + } + switch (kioskParameters.KioskMode) + { + case KioskMode.Vehicle: + { + var kioskResult = _vehicleLogic.GetVehicleInfo(vehiclesStored); + return PartialView("_Kiosk", kioskResult); + } + case KioskMode.Plan: + { + var kioskResult = _vehicleLogic.GetPlans(vehiclesStored, true); + return PartialView("_KioskPlan", kioskResult); + } + break; + case KioskMode.Reminder: + { + var kioskResult = _vehicleLogic.GetReminders(vehiclesStored, false); + return PartialView("_KioskReminder", kioskResult); + } + } var result = _vehicleLogic.GetVehicleInfo(vehiclesStored); return PartialView("_Kiosk", result); } @@ -140,19 +171,7 @@ namespace CarCareTracker.Controllers { vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID()); } - List reminders = new List(); - foreach (Vehicle vehicle in vehiclesStored) - { - var vehicleReminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicle.Id); - vehicleReminders.RemoveAll(x => x.Metric == ReminderMetric.Odometer); - //we don't care about mileages so we can basically fake the current vehicle mileage. - if (vehicleReminders.Any()) - { - var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(vehicleReminders, 0, DateTime.Now); - reminderUrgency = reminderUrgency.Select(x => new ReminderRecordViewModel { Id = x.Id, Date = x.Date, Urgency = x.Urgency, Description = $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{StaticHelper.GetVehicleIdentifier(vehicle)} - {x.Description}" }).ToList(); - reminders.AddRange(reminderUrgency); - } - } + var reminders = _vehicleLogic.GetReminders(vehiclesStored, true); return PartialView("_Calendar", reminders); } public IActionResult ViewCalendarReminder(int reminderId) diff --git a/Enum/KioskMode.cs b/Enum/KioskMode.cs new file mode 100644 index 0000000..a246d5f --- /dev/null +++ b/Enum/KioskMode.cs @@ -0,0 +1,10 @@ +namespace CarCareTracker.Models +{ + public enum KioskMode + { + Vehicle = 0, + Plan = 1, + Reminder = 2, + Cycle = 3 + } +} diff --git a/Helper/StaticHelper.cs b/Helper/StaticHelper.cs index 35cf715..a9f12fc 100644 --- a/Helper/StaticHelper.cs +++ b/Helper/StaticHelper.cs @@ -46,6 +46,52 @@ namespace CarCareTracker.Helper return input; } } + public static string GetReminderUrgencyColor(ReminderUrgency input) + { + switch (input) + { + case ReminderUrgency.NotUrgent: + return "text-bg-success"; + case ReminderUrgency.VeryUrgent: + return "text-bg-danger"; + case ReminderUrgency.PastDue: + return "text-bg-secondary"; + default: + return "text-bg-warning"; + } + } + + public static string GetPlanRecordColor(PlanPriority input) + { + switch (input) + { + case PlanPriority.Critical: + return "text-bg-danger"; + case PlanPriority.Normal: + return "text-bg-primary"; + case PlanPriority.Low: + return "text-bg-info"; + default: + return "text-bg-primary"; + } + } + + public static string GetPlanRecordProgress(PlanProgress input) + { + switch (input) + { + case PlanProgress.Backlog: + return "Planned"; + case PlanProgress.InProgress: + return "Doing"; + case PlanProgress.Testing: + return "Testing"; + case PlanProgress.Done: + return "Done"; + default: + return input.ToString(); + } + } public static string TruncateStrings(string input, int maxLength = 25) { diff --git a/Logic/VehicleLogic.cs b/Logic/VehicleLogic.cs index 3df2425..cb2774f 100644 --- a/Logic/VehicleLogic.cs +++ b/Logic/VehicleLogic.cs @@ -15,6 +15,8 @@ namespace CarCareTracker.Logic int GetOwnershipDays(string purchaseDate, string soldDate, List serviceRecords, List repairRecords, List gasRecords, List upgradeRecords, List odometerRecords, List taxRecords); bool GetVehicleHasUrgentOrPastDueReminders(int vehicleId, int currentMileage); List GetVehicleInfo(List vehicles); + List GetReminders(List vehicles, bool isCalendar); + List GetPlans(List vehicles, bool excludeDone); } public class VehicleLogic: IVehicleLogic { @@ -276,5 +278,44 @@ namespace CarCareTracker.Logic } return apiResult; } + public List GetReminders(List vehicles, bool isCalendar) + { + List reminders = new List(); + foreach (Vehicle vehicle in vehicles) + { + var vehicleReminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicle.Id); + if (isCalendar) + { + vehicleReminders.RemoveAll(x => x.Metric == ReminderMetric.Odometer); + //we don't care about mileages so we can basically fake the current vehicle mileage. + } + if (vehicleReminders.Any()) + { + var vehicleMileage = isCalendar ? 0 : GetMaxMileage(vehicle.Id); + var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(vehicleReminders, vehicleMileage, DateTime.Now); + reminderUrgency = reminderUrgency.Select(x => new ReminderRecordViewModel { Id = x.Id, Metric = x.Metric, Date = x.Date, Notes = x.Notes, Mileage = x.Mileage, Urgency = x.Urgency, Description = $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{StaticHelper.GetVehicleIdentifier(vehicle)} - {x.Description}" }).ToList(); + reminders.AddRange(reminderUrgency); + } + } + return reminders.OrderByDescending(x=>x.Urgency).ToList(); + } + public List GetPlans(List vehicles, bool excludeDone) + { + List plans = new List(); + foreach (Vehicle vehicle in vehicles) + { + var vehiclePlans = _planRecordDataAccess.GetPlanRecordsByVehicleId(vehicle.Id); + if (excludeDone) + { + vehiclePlans.RemoveAll(x => x.Progress == PlanProgress.Done); + } + if (vehiclePlans.Any()) + { + var convertedPlans = vehiclePlans.Select(x => new PlanRecord { Priority = x.Priority, Progress = x.Progress, Notes = x.Notes, RequisitionHistory = x.RequisitionHistory, Description = $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{StaticHelper.GetVehicleIdentifier(vehicle)} - {x.Description}" }); + plans.AddRange(convertedPlans); + } + } + return plans.OrderBy(x => x.Priority).ThenBy(x=>x.Progress).ToList(); + } } } diff --git a/Models/Kiosk/KioskViewModel.cs b/Models/Kiosk/KioskViewModel.cs new file mode 100644 index 0000000..7eacf38 --- /dev/null +++ b/Models/Kiosk/KioskViewModel.cs @@ -0,0 +1,14 @@ +namespace CarCareTracker.Models +{ + public class KioskViewModel + { + /// + /// List of vehicle ids to exclude from Kiosk Dashboard + /// + public List Exclusions { get; set; } = new List(); + /// + /// Whether to retrieve data for vehicle, plans, or reminder view. + /// + public KioskMode KioskMode { get; set; } = KioskMode.Vehicle; + } +} diff --git a/README.md b/README.md index ee82269..dc739b3 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Read this [Getting Started Guide](https://docs.lubelogger.com/Installation/Getti - [Chart.js](https://github.com/chartjs/Chart.js) - [Drawdown](https://github.com/adamvleggett/drawdown) - [MailKit](https://github.com/jstedfast/MailKit) +- [Masonry](https://github.com/desandro/masonry) ## License MIT diff --git a/Views/API/Index.cshtml b/Views/API/Index.cshtml index bc274dc..140e15c 100644 --- a/Views/API/Index.cshtml +++ b/Views/API/Index.cshtml @@ -116,6 +116,7 @@ initialOdometer - Initial Odometer reading(optional)
odometer - Odometer reading
notes - notes(optional)
+ tags - tags separated by space(optional)
extrafields - extrafields(optional)
} @@ -153,6 +154,7 @@ description - Description
cost - Cost
notes - notes(optional)
+ tags - tags separated by space(optional)
extrafields - extrafields(optional)
} @@ -190,6 +192,7 @@ description - Description
cost - Cost
notes - notes(optional)
+ tags - tags separated by space(optional)
extrafields - extrafields(optional)
} @@ -227,6 +230,7 @@ description - Description
cost - Cost
notes - notes(optional)
+ tags - tags separated by space(optional)
extrafields - extrafields(optional)
} @@ -263,6 +267,7 @@ description - Description
cost - Cost
notes - notes(optional)
+ tags - tags separated by space(optional)
extrafields - extrafields(optional)
} @@ -306,6 +311,7 @@ isFillToFull(bool) - Filled To Full
missedFuelUp(bool) - Missed Fuel Up
notes - notes(optional)
+ tags - tags separated by space(optional)
extrafields - extrafields(optional)
} diff --git a/Views/Home/Kiosk.cshtml b/Views/Home/Kiosk.cshtml index 57acb0b..369a3b2 100644 --- a/Views/Home/Kiosk.cshtml +++ b/Views/Home/Kiosk.cshtml @@ -1,7 +1,10 @@ @{ ViewData["Title"] = "Kiosk"; } -@model List +@model KioskViewModel +@section Scripts { + +}
@@ -11,8 +14,11 @@ let refreshTimer; let exceptionList = []; let subtractAmount = 0; + let kioskMode = '@Model.KioskMode'; + let currentKioskMode = 'Plan'; + let kioskWakeLock; - @foreach(int exception in Model) + @foreach(int exception in Model.Exclusions) { @:exceptionList.push(@exception); } @@ -25,14 +31,56 @@ subtractAmount = 2; } retrieveKioskContent(); + //acquire wakeLock; + try { + navigator.wakeLock.request('screen').then((wl) => { + kioskWakeLock = wl; + }); + } catch (err) { + errorToast('Location Services not Enabled'); + } } function retrieveKioskContent(){ clearInterval(refreshTimer); - $.post('/Home/KioskContent', {exceptionList: exceptionList}, function (data) { - $("#kioskContainer").html(data); - $(".progress-bar").width($("#kioskContainer").width()); - setTimeout(function () { startTimer() }, 500); - }); + if (kioskMode != 'Cycle'){ + $.post('/Home/KioskContent', { exclusions: exceptionList, kioskMode: kioskMode }, function (data) { + $("#kioskContainer").html(data); + $(".kiosk-content").masonry(); + if ($(".no-data-message").length == 0) { + $(".progress-bar").width($("#kioskContainer").width()); + setTimeout(function () { startTimer() }, 500); + } + }); + } else { + //cycle mode + switch (currentKioskMode) { + case "Vehicle": + currentKioskMode = "Reminder"; + break; + case "Reminder": + currentKioskMode = "Plan"; + break; + case "Plan": + currentKioskMode = "Vehicle"; + break; + } + $.post('/Home/KioskContent', { exclusions: exceptionList, kioskMode: currentKioskMode }, function (data) { + $("#kioskContainer").html(data); + $(".kiosk-content").masonry(); + if ($(".no-data-message").length > 0) { + //if no data on vehicle page + if (currentKioskMode == "Vehicle") { + return; //exit + } else { + retrieveKioskContent(); //skip until we hit a page with content. + } + } else { + $(".progress-bar").width($("#kioskContainer").width()); + setTimeout(function () { startTimer() }, 500); + } + }); + } + } function startTimer() { refreshTimer = setInterval(function () { @@ -45,6 +93,9 @@ }, 100); } function addVehicleToExceptionList(vehicleId) { + if (kioskMode == 'Cycle') { + return; + } Swal.fire({ title: "Remove Vehicle from Dashboard?", text: "Removed vehicles can be restored by refreshing the page", @@ -58,5 +109,28 @@ } }); } + function toggleReminderNote(sender){ + var reminderNote = $(sender).find('.reminder-note'); + if (reminderNote.text().trim() != ''){ + if (reminderNote.hasClass('d-none')) { + reminderNote.removeClass('d-none'); + } else { + reminderNote.addClass('d-none'); + } + $(".kiosk-content").masonry(); + } + } + function togglePlanDetails(sender) { + toggleReminderNote(sender); + var planSupplies = $(sender).find('.plan-supplies'); + if (planSupplies.find('.plan-supply').length > 0) { + if (planSupplies.hasClass('d-none')) { + planSupplies.removeClass('d-none'); + } else { + planSupplies.addClass('d-none'); + } + $(".kiosk-content").masonry(); + } + } initKiosk(); \ No newline at end of file diff --git a/Views/Home/_Kiosk.cshtml b/Views/Home/_Kiosk.cshtml index f5165bd..71fe6bd 100644 --- a/Views/Home/_Kiosk.cshtml +++ b/Views/Home/_Kiosk.cshtml @@ -6,10 +6,10 @@ var userConfig = config.GetUserConfig(User); var userLanguage = userConfig.UserLanguage; } -
- @foreach(VehicleInfo vehicle in Model) - { - @if (!(userConfig.HideSoldVehicles && !string.IsNullOrWhiteSpace(vehicle.VehicleData.SoldDate))) +@if (Model.Any()) +{ +
+ @foreach (VehicleInfo vehicle in Model) {
@@ -65,7 +65,7 @@ } @if (vehicle.NextReminder != null) { -
+
@translator.Translate(userLanguage, "Upcoming Reminder")
@@ -112,7 +112,15 @@
}
-
+
} - } -
\ No newline at end of file +
+} +else +{ +
+
+ @translator.Translate(userLanguage, "No records available to display") +
+
+} diff --git a/Views/Home/_KioskPlan.cshtml b/Views/Home/_KioskPlan.cshtml new file mode 100644 index 0000000..5f65dd3 --- /dev/null +++ b/Views/Home/_KioskPlan.cshtml @@ -0,0 +1,86 @@ +@using CarCareTracker.Helper +@model List +@inject IConfigHelper config +@inject ITranslationHelper translator +@{ + var userConfig = config.GetUserConfig(User); + var userLanguage = userConfig.UserLanguage; +} +@if (Model.Any()) +{ +
+ @foreach (PlanRecord plan in Model) + { +
+
+
+
@plan.Description
+
+
+

@plan.Notes

+

@translator.Translate(userLanguage, StaticHelper.GetPlanRecordProgress(plan.Progress))

+
+
+ @if (plan.ImportMode == ImportMode.ServiceRecord) + { + @translator.Translate(userLanguage, "Service") + } + else if (plan.ImportMode == ImportMode.UpgradeRecord) + { + @translator.Translate(userLanguage, "Repairs") + } + else if (plan.ImportMode == ImportMode.RepairRecord) + { + @translator.Translate(userLanguage, "Upgrades") + } +
+
+
+
+
+ @if (plan.RequisitionHistory.Any()) + { +
    +
  • +
    +
    + @translator.Translate(userLanguage, "Part Number") +
    +
    + @translator.Translate(userLanguage, "Description") +
    +
    + @translator.Translate(userLanguage, "Quantity") +
    +
    +
  • + @foreach (SupplyUsageHistory supply in plan.RequisitionHistory) + { +
  • +
    +
    + @supply.PartNumber +
    +
    + @supply.Description +
    +
    + @supply.Quantity +
    +
    +
  • + } +
+ } +
+
+ } +
+} else +{ +
+
+ @translator.Translate(userLanguage, "No records available to display") +
+
+} \ No newline at end of file diff --git a/Views/Home/_KioskReminder.cshtml b/Views/Home/_KioskReminder.cshtml new file mode 100644 index 0000000..ef0ede0 --- /dev/null +++ b/Views/Home/_KioskReminder.cshtml @@ -0,0 +1,47 @@ +@using CarCareTracker.Helper +@model List +@inject IConfigHelper config +@inject ITranslationHelper translator +@{ + var userConfig = config.GetUserConfig(User); + var userLanguage = userConfig.UserLanguage; +} +@if (Model.Any()) +{ +
+ @foreach (ReminderRecordViewModel reminder in Model) + { +
+
+
+
@reminder.Description
+
+
+

@reminder.Notes

+

@translator.Translate(userLanguage, StaticHelper.GetTitleCaseReminderUrgency(reminder.Urgency))

+
+ @if (reminder.Metric == ReminderMetric.Date || reminder.Metric == ReminderMetric.Both) + { +
@reminder.Date.ToShortDateString()
+ } + @if (reminder.Metric == ReminderMetric.Odometer || reminder.Metric == ReminderMetric.Both) + { +
@reminder.Mileage
+ } +
+
+
+
+
+
+ } +
+} +else +{ +
+
+ @translator.Translate(userLanguage, "No records available to display") +
+
+} \ No newline at end of file diff --git a/Views/Home/_Settings.cshtml b/Views/Home/_Settings.cshtml index b6f3898..88c1cdb 100644 --- a/Views/Home/_Settings.cshtml +++ b/Views/Home/_Settings.cshtml @@ -308,6 +308,7 @@
  • Chart.js
  • Drawdown
  • MailKit
  • +
  • Masonry
  • diff --git a/wwwroot/defaults/en_US.json b/wwwroot/defaults/en_US.json index 58472db..dec1798 100644 --- a/wwwroot/defaults/en_US.json +++ b/wwwroot/defaults/en_US.json @@ -1 +1 @@ -{"Garage":"Garage","Settings":"Settings","Admin_Panel":"Admin Panel","Logout":"Logout","Dark_Mode":"Dark Mode","Enable_CSV_Imports":"Enable CSV Imports","Use_Imperial_Calculation_for_Fuel_Economy_Calculations(MPG)":"Use Imperial Calculation for Fuel Economy Calculations(MPG)","This_Will_Also_Change_Units_to_Miles_and_Gallons":"This Will Also Change Units to Miles and Gallons","Use_UK_MPG_Calculation":"Use UK MPG Calculation","Input_Gas_Consumption_in_Liters,_it_will_be_converted_to_UK_Gals_for_MPG_Calculation":"Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation","Sort_lists_in_Descending_Order(Newest_to_Oldest)":"Sort lists in Descending Order(Newest to Oldest)","Replace_$0.00_Costs_with_---":"Replace $0.00 Costs with ---","Use_Three_Decimals_For_Fuel_Cost":"Use Three Decimals For Fuel Cost","Display_Saved_Notes_in_Markdown":"Display Saved Notes in Markdown","Auto_Refresh_Lapsed_Recurring_Reminders":"Auto Refresh Lapsed Recurring Reminders","Auto_Insert_Odometer_Records":"Auto Insert Odometer Records","Only_when_Adding_Service/Repair/Upgrade/Fuel_Record_or_Completing_a_Plan":"Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan","Enable_Authentication":"Enable Authentication","Visible_Tabs":"Visible Tabs","Service_Records":"Service Records","Dashboard":"Dashboard","Repairs":"Repairs","Upgrades":"Upgrades","Fuel":"Fuel","Odometer":"Odometer","Taxes":"Taxes","Notes":"Notes","Reminder":"Reminder","Supplies":"Supplies","Planner":"Planner","Default_Tab":"Default Tab","Service_Record":"Service Record","Tax":"Tax","Reminders":"Reminders","Backups":"Backups","Make":"Make","Restore":"Restore","About":"About","Add_New_Vehicle":"Add New Vehicle","Year":"Year","Year(must_be_after_1900)":"Year(must be after 1900)","Model":"Model","License_Plate":"License Plate","Electric_Vehicle":"Electric Vehicle","Use_Engine_Hours":"Use Engine Hours","Tags(optional)":"Tags(optional)","Upload_a_picture(optional)":"Upload a picture(optional)","Cancel":"Cancel","Edit_Vehicle":"Edit Vehicle","Delete_Vehicle":"Delete Vehicle","Manage_Vehicle":"Manage Vehicle","Expenses_by_Type":"Expenses by Type","Service":"Service","Expenses_by_Month":"Expenses by Month","As_of_Today":"As of Today","\u002B30_Days":"\u002B30 Days","\u002B60_Days":"\u002B60 Days","\u002B90_Days":"\u002B90 Days","Not_Urgent":"Not Urgent","Urgent":"Urgent","Very_Urgent":"Very Urgent","Past_Due":"Past Due","Reminders_by_Category":"Reminders by Category","Reminders_by_Urgency":"Reminders by Urgency","Collaborators":"Collaborators","Username":"Username","Delete":"Delete","Fuel_Mileage_by_Month":"Fuel Mileage by Month","Vehicle_Maintenance_Report":"Vehicle Maintenance Report","Export_Attachments":"Export Attachments","Gasoline":"Gasoline","Last_Reported_Odometer_Reading":"Last Reported Odometer Reading","Average_Fuel_Economy":"Average Fuel Economy","Total_Spent(excl._fuel)":"Total Spent(excl. fuel)","Total_Spent_on_Fuel":"Total Spent on Fuel","Type":"Type","Date":"Date","Description":"Description","Cost":"Cost","Repair":"Repair","Upgrade":"Upgrade","#_of_Odometer_Records":"# of Odometer Records","Add_Odometer_Record":"Add Odometer Record","Import_via_CSV":"Import via CSV","Export_to_CSV":"Export to CSV","Print":"Print","Add_New_Odometer_Record":"Add New Odometer Record","Date_recorded":"Date recorded","Odometer_reading":"Odometer reading","Notes(optional)":"Notes(optional)","Upload_documents(optional)":"Upload documents(optional)","Max_File_Size:_28.6MB":"Max File Size: 28.6MB","#_of_Service_Records":"# of Service Records","Total":"Total","Add_Service_Record":"Add Service Record","No_data_found,_create_reminders_to_see_visualizations_here.":"No data found, create reminders to see visualizations here.","No_data_found,_insert/select_some_data_to_see_visualizations_here.":"No data found, insert/select some data to see visualizations here.","Edit_Odometer_Record":"Edit Odometer Record","Import_Data_from_CSV":"Import Data from CSV","In_order_for_this_utility_to_function_properly,_your_CSV_file_MUST_be_formatted_exactly_like_the_provided_sample._Dates_must_be_supplied_in_a_string._Numbers_must_be_supplied_as_numbers_without_currency_formatting.":"In order for this utility to function properly, your CSV file MUST be formatted exactly like the provided sample. Dates must be supplied in a string. Numbers must be supplied as numbers without currency formatting.","Failure_to_format_the_data_correctly_can_cause_data_corruption._Please_make_sure_you_make_a_copy_of_the_local_database_before_proceeding.":"Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.","Download_Sample":"Download Sample","Upload_CSV_File":"Upload CSV File","Import":"Import","Edit_Service_Record":"Edit Service Record","Date_service_was_performed":"Date service was performed","Odometer_reading_when_serviced":"Odometer reading when serviced","Description_of_item(s)_serviced(i.e._Oil_Change)":"Description of item(s) serviced(i.e. Oil Change)","Cost_of_the_service":"Cost of the service","Move_To":"Move To","#_of_Repair_Records":"# of Repair Records","Add_Repair_Record":"Add Repair Record","Add_New_Repair_Record":"Add New Repair Record","Date_repair_was_performed":"Date repair was performed","Odometer_reading_when_repaired":"Odometer reading when repaired","Description_of_item(s)_repaired(i.e._Alternator)":"Description of item(s) repaired(i.e. Alternator)","Cost_of_the_repair":"Cost of the repair","Choose_Supplies":"Choose Supplies","Add_Reminder":"Add Reminder","Select_Supplies":"Select Supplies","No_supplies_with_quantities_greater_than_0_is_found.":"No supplies with quantities greater than 0 is found.","Select":"Select","#_of_Upgrade_Records":"# of Upgrade Records","Add_Upgrade_Record":"Add Upgrade Record","Add_New_Upgrade_Record":"Add New Upgrade Record","Date_upgrade/mods_was_installed":"Date upgrade/mods was installed","Odometer_reading_when_upgraded/modded":"Odometer reading when upgraded/modded","Description_of_item(s)_upgraded/modded":"Description of item(s) upgraded/modded","Cost_of_the_upgrade/mods":"Cost of the upgrade/mods","#_of_Gas_Records":"# of Gas Records","Total_Fuel_Consumed":"Total Fuel Consumed","Total_Cost":"Total Cost","Add_Gas_Record":"Add Gas Record","Date_Refueled":"Date Refueled","Consumption":"Consumption","Fuel_Economy":"Fuel Economy","Unit_Cost":"Unit Cost","#_of_Supply_Records":"# of Supply Records","Add_Supply_Record":"Add Supply Record","Part_#":"Part #","Supplier":"Supplier","Quantity":"Quantity","Add_New_Supply_Record":"Add New Supply Record","Date_purchased":"Date purchased","Part_Number":"Part Number","Part_#/Model_#/SKU_#":"Part #/Model #/SKU #","Description_of_the_Part/Supplies":"Description of the Part/Supplies","Supplier/Vendor":"Supplier/Vendor","Part_Supplier":"Part Supplier","Edit_Supply_Record":"Edit Supply Record","Add_New_Service_Record":"Add New Service Record","Supplies_are_requisitioned_immediately_after_the_record_is_created_and_cannot_be_modified._If_you_have_incorrectly_entered_the_amount_you_needed_you_will_need_to_correct_it_in_the_Supplies_tab.":"Supplies are requisitioned immediately after the record is created and cannot be modified. If you have incorrectly entered the amount you needed you will need to correct it in the Supplies tab.","In_Stock":"In Stock","Edit_Repair_Record":"Edit Repair Record","Edit_Upgrade_Record":"Edit Upgrade Record","Save_Vehicle":"Save Vehicle","Add_New_Gas_Record":"Add New Gas Record","Date_refueled":"Date refueled","Odometer_Reading":"Odometer Reading","Odometer_reading_when_refueled":"Odometer reading when refueled","Fuel_Consumption":"Fuel Consumption","Amount_of_gas_refueled":"Amount of gas refueled","Is_Filled_To_Full":"Is Filled To Full","Missed_Fuel_Up(Skip_MPG_Calculation)":"Missed Fuel Up(Skip MPG Calculation)","Cost_of_gas_refueled":"Cost of gas refueled","Unit":"Unit","#_of_Tax_Records":"# of Tax Records","Add_Tax_Record":"Add Tax Record","Add_New_Tax_Record":"Add New Tax Record","Date_tax_was_paid":"Date tax was paid","Description_of_tax_paid(i.e._Registration)":"Description of tax paid(i.e. Registration)","Cost_of_tax_paid":"Cost of tax paid","Is_Recurring":"Is Recurring","Month":"Month","1_Month":"1 Month","3_Months":"3 Months","6_Months":"6 Months","1_Year":"1 Year","2_Years":"2 Years","3_Years":"3 Years","5_Years":"5 Years","Edit_Tax_Record":"Edit Tax Record","#_of_Notes":"# of Notes","Add_Note":"Add Note","Note":"Note","Add_New_Note":"Add New Note","Pinned":"Pinned","Description_of_the_note":"Description of the note","Min_Fuel_Economy":"Min Fuel Economy","Max_Fuel_Economy":"Max Fuel Economy","Edit_Gas_Record":"Edit Gas Record","#_of_Plan_Records":"# of Plan Records","Add_Plan_Record":"Add Plan Record","Planned":"Planned","Doing":"Doing","Testing":"Testing","Done":"Done","Add_New_Plan_Record":"Add New Plan Record","Describe_the_Plan":"Describe the Plan","Cost_of_the_Plan":"Cost of the Plan","Priority":"Priority","Critical":"Critical","Normal":"Normal","Low":"Low","Current_Stage":"Current Stage","#_of_Reminders":"# of Reminders","Urgency":"Urgency","Metric":"Metric","Add_New_Reminder":"Add New Reminder","Reminder_Description":"Reminder Description","Remind_me_on":"Remind me on","Future_Date":"Future Date","Future_Odometer_Reading":"Future Odometer Reading","Whichever_comes_first":"Whichever comes first","Other":"Other","Edit_Reminder":"Edit Reminder","Replace_picture(optional)":"Replace picture(optional)","Language":"Language","Manage_Languages":"Manage Languages","Upload":"Upload","Tokens":"Tokens","Generate_User_Token":"Generate User Token","Auto_Notify(via_Email)":"Auto Notify(via Email)","Token":"Token","Issued_To":"Issued To","Users":"Users","Email":"Email","Is_Admin":"Is Admin","An_error_has_occurred,_please_try_again_later":"An error has occurred, please try again later","Edit_Note":"Edit Note","Password":"Password","Remember_Me":"Remember Me","Login":"Login","Forgot_Password":"Forgot Password","Register":"Register","Request":"Request","I_Have_a_Token":"I Have a Token","Back_to_Login":"Back to Login","Email_Address":"Email Address","New_Password":"New Password","Reset_Password":"Reset Password","No_data_found_or_all_records_have_zero_sums,_insert_records_with_non-zero_sums_to_see_visualizations_here.":"No data found or all records have zero sums, insert records with non-zero sums to see visualizations here.","Save_as_Template":"Save as Template","View_Templates":"View Templates","Select_Template":"Select Template","No_templates_are_found.":"No templates are found.","Use":"Use","Edit_Plan_Record":"Edit Plan Record","Date_Created":"Date Created","Last_Modified":"Last Modified","Shop_Supplies":"Shop Supplies","Uploaded_Documents":"Uploaded Documents","Upload_more_documents":"Upload more documents","Database_Migration":"Database Migration","Instructions":"Instructions","To_Postgres":"To Postgres","From_Postgres":"From Postgres","Import_To_Postgres":"Import To Postgres","Export_From_Postgres":"Export From Postgres","Create":"Create","Manage_Extra_Fields":"Manage Extra Fields","Add/Remove_Extra_Fields":"Add/Remove Extra Fields","Name":"Name","Required":"Required","Add_New_Field":"Add New Field","Close":"Close","Calendar":"Calendar","View_Reminder":"View Reminder","Mark_as_Done":"Mark as Done","Login_via":"Login via","Distance_Traveled_by_Month":"Distance Traveled by Month","Expenses_and_Distance_Traveled_by_Month":"Expenses and Distance Traveled by Month","Select_All":"Select All","Supply_Requisition_History":"Supply Requisition History","No_supply_requisitions_in_history":"No supply requisitions in history","Plan":"Plan","Deselect_All":"Deselect All","Duplicate":"Duplicate","Toggle_Pin":"Toggle Pin","Pin":"Pin","Unpin":"Unpin","Profile":"Profile","Update_Profile":"Update Profile","Account_Username":"Account Username","Send_Token":"Send Token","Update":"Update","Show_Extra_Field_Columns":"Show Extra Field Columns","Enabling_this_may_cause_performance_issues":"Enabling this may cause performance issues","Visible_Columns":"Visible Columns","Edit_Multiple":"Edit Multiple","Edit_Multiple_Records":"Edit Multiple Records","(multiple)":"(multiple)","Tags(use_---_to_clear_all_existing_tags)":"Tags(use --- to clear all existing tags)","Notes(use_---_to_clear_all_existing_notes)":"Notes(use --- to clear all existing notes)","Edit":"Edit","Search":"Search","Delta":"Delta","Vehicle":"Vehicle","Select_Reminder":"Select Reminder","Purchased_Date(optional)":"Purchased Date(optional)","Purchased_Date":"Purchased Date","Sold_Date(optional)":"Sold Date(optional)","Sold_Date":"Sold Date","SOLD":"SOLD","Days":"Days","Statistics":"Statistics","Hide_Sold_Vehicles":"Hide Sold Vehicles","Server-wide_Settings":"Server-wide Settings","Extra_Fields":"Extra Fields","Version":"Version","Configure_Reminder_Urgency_Thresholds":"Configure Reminder Urgency Thresholds","Urgent(Days)":"Urgent(Days)","Very_Urgent(Days)":"Very Urgent(Days)","Urgent(Distance)":"Urgent(Distance)","Very_Urgent(Distance)":"Very Urgent(Distance)","Save":"Save","Initial_Odometer":"Initial Odometer","Distance":"Distance","Initial_Odometer_reading":"Initial Odometer reading","Total_Distance":"Total Distance","Recalculate_Distance":"Recalculate Distance","Edit_Multiple_Odometer_Records":"Edit Multiple Odometer Records","Odometer_Adjustments":"Odometer Adjustments","Odometer_Multiplier":"Odometer Multiplier","Odometer_Difference":"Odometer Difference","Adjust_Odometer":"Adjust Odometer","Edit_Multiple_Gas_Records":"Edit Multiple Gas Records","Multiple":"Multiple","Copy_Attachments":"Copy Attachments","Purchased_Price(optional)":"Purchased Price(optional)","Purchased_Price":"Purchased Price","Sold_Price(optional)":"Sold Price(optional)","Sold_Price":"Sold Price","Purchase/Sold_Information(optional)":"Purchase/Sold Information(optional)","Electric":"Electric","Depreciation":"Depreciation","day":"day","Appreciation":"Appreciation","Search_by_Keyword(Case_Sensitive)":"Search by Keyword(Case Sensitive)","Incremental_Search":"Incremental Search","Unsaved_Changes":"Unsaved Changes","Edit_Plan_Record_Template":"Edit Plan Record Template","No_Data_Found":"No Data Found","Sponsors":"Sponsors","All_Time":"All Time","Metrics":"Metrics","gallons":"gallons","miles":"miles","liters":"liters","kilometers":"kilometers","Fuel_Type":"Fuel Type","Diesel":"Diesel","Documents_Pending_Upload":"Documents Pending Upload","Vehicle_Cost_Breakdown":"Vehicle Cost Breakdown","Cost_Per_Day":"Cost Per Day","Cost_Per_Mile":"Cost Per Mile","Cost_Per_Kilometer":"Cost Per Kilometer","Cost_Per_Hour":"Cost Per Hour","Dashboard_Metrics":"Dashboard Metrics","Last_Odometer":"Last Odometer","Total_Cost_/_Total_Distance_Driven":"Total Cost / Total Distance Driven","Use_Custom_Thresholds":"Use Custom Thresholds","Disable_Registration":"Disable Registration","Default_Reminder_Email":"Default Reminder Email","Default_Email_for_Reminder":"Default Email for Reminder","Enable_OIDC_for_Root_User":"Enable OIDC for Root User","Adaptive_Color_Mode":"Adaptive Color Mode","Uses_the_Default_Reminder_Email_for_OIDC_Auth":"Uses the Default Reminder Email for OIDC Auth","Odometer_Optional":"Odometer Optional","Manage_Tokens":"Manage Tokens","Generate":"Generate","Notify":"Notify","Start_Recording":"Start Recording","Stop_Recording":"Stop Recording","Current_Odometer":"Current Odometer","Experimental_Feature_-_Do_not_exit_or_minimize_this_app_when_recording._Verify_all_starting_and_ending_odometers._Accuracy_subject_to_hardware_limitations.":"Experimental Feature - Do not exit or minimize this app when recording. Verify all starting and ending odometers. Accuracy subject to hardware limitations.","Identifier":"Identifier","Translation_Editor":"Translation Editor","Save_Translation":"Save Translation","Export_Translation":"Export Translation","Get_Translations":"Get Translations","Available_Translations":"Available Translations","Download_All_Translations":"Download All Translations","Reorder_Tabs":"Reorder Tabs","Reset_Tab_Order":"Reset Tab Order","Save_Tab_Order":"Save Tab Order","Upcoming_Reminder":"Upcoming Reminder","Plans":"Plans"} \ No newline at end of file +{"Garage":"Garage","Settings":"Settings","Admin_Panel":"Admin Panel","Logout":"Logout","Dark_Mode":"Dark Mode","Enable_CSV_Imports":"Enable CSV Imports","Use_Imperial_Calculation_for_Fuel_Economy_Calculations(MPG)":"Use Imperial Calculation for Fuel Economy Calculations(MPG)","This_Will_Also_Change_Units_to_Miles_and_Gallons":"This Will Also Change Units to Miles and Gallons","Use_UK_MPG_Calculation":"Use UK MPG Calculation","Input_Gas_Consumption_in_Liters,_it_will_be_converted_to_UK_Gals_for_MPG_Calculation":"Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation","Sort_lists_in_Descending_Order(Newest_to_Oldest)":"Sort lists in Descending Order(Newest to Oldest)","Replace_$0.00_Costs_with_---":"Replace $0.00 Costs with ---","Use_Three_Decimals_For_Fuel_Cost":"Use Three Decimals For Fuel Cost","Display_Saved_Notes_in_Markdown":"Display Saved Notes in Markdown","Auto_Refresh_Lapsed_Recurring_Reminders":"Auto Refresh Lapsed Recurring Reminders","Auto_Insert_Odometer_Records":"Auto Insert Odometer Records","Only_when_Adding_Service/Repair/Upgrade/Fuel_Record_or_Completing_a_Plan":"Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan","Enable_Authentication":"Enable Authentication","Visible_Tabs":"Visible Tabs","Service_Records":"Service Records","Dashboard":"Dashboard","Repairs":"Repairs","Upgrades":"Upgrades","Fuel":"Fuel","Odometer":"Odometer","Taxes":"Taxes","Notes":"Notes","Reminder":"Reminder","Supplies":"Supplies","Planner":"Planner","Default_Tab":"Default Tab","Service_Record":"Service Record","Tax":"Tax","Reminders":"Reminders","Backups":"Backups","Make":"Make","Restore":"Restore","About":"About","Add_New_Vehicle":"Add New Vehicle","Year":"Year","Year(must_be_after_1900)":"Year(must be after 1900)","Model":"Model","License_Plate":"License Plate","Electric_Vehicle":"Electric Vehicle","Use_Engine_Hours":"Use Engine Hours","Tags(optional)":"Tags(optional)","Upload_a_picture(optional)":"Upload a picture(optional)","Cancel":"Cancel","Edit_Vehicle":"Edit Vehicle","Delete_Vehicle":"Delete Vehicle","Manage_Vehicle":"Manage Vehicle","Expenses_by_Type":"Expenses by Type","Service":"Service","Expenses_by_Month":"Expenses by Month","As_of_Today":"As of Today","\u002B30_Days":"\u002B30 Days","\u002B60_Days":"\u002B60 Days","\u002B90_Days":"\u002B90 Days","Not_Urgent":"Not Urgent","Urgent":"Urgent","Very_Urgent":"Very Urgent","Past_Due":"Past Due","Reminders_by_Category":"Reminders by Category","Reminders_by_Urgency":"Reminders by Urgency","Collaborators":"Collaborators","Username":"Username","Delete":"Delete","Fuel_Mileage_by_Month":"Fuel Mileage by Month","Vehicle_Maintenance_Report":"Vehicle Maintenance Report","Export_Attachments":"Export Attachments","Gasoline":"Gasoline","Last_Reported_Odometer_Reading":"Last Reported Odometer Reading","Average_Fuel_Economy":"Average Fuel Economy","Total_Spent(excl._fuel)":"Total Spent(excl. fuel)","Total_Spent_on_Fuel":"Total Spent on Fuel","Type":"Type","Date":"Date","Description":"Description","Cost":"Cost","Repair":"Repair","Upgrade":"Upgrade","#_of_Odometer_Records":"# of Odometer Records","Add_Odometer_Record":"Add Odometer Record","Import_via_CSV":"Import via CSV","Export_to_CSV":"Export to CSV","Print":"Print","Add_New_Odometer_Record":"Add New Odometer Record","Date_recorded":"Date recorded","Odometer_reading":"Odometer reading","Notes(optional)":"Notes(optional)","Upload_documents(optional)":"Upload documents(optional)","Max_File_Size:_28.6MB":"Max File Size: 28.6MB","#_of_Service_Records":"# of Service Records","Total":"Total","Add_Service_Record":"Add Service Record","No_data_found,_create_reminders_to_see_visualizations_here.":"No data found, create reminders to see visualizations here.","No_data_found,_insert/select_some_data_to_see_visualizations_here.":"No data found, insert/select some data to see visualizations here.","Edit_Odometer_Record":"Edit Odometer Record","Import_Data_from_CSV":"Import Data from CSV","In_order_for_this_utility_to_function_properly,_your_CSV_file_MUST_be_formatted_exactly_like_the_provided_sample._Dates_must_be_supplied_in_a_string._Numbers_must_be_supplied_as_numbers_without_currency_formatting.":"In order for this utility to function properly, your CSV file MUST be formatted exactly like the provided sample. Dates must be supplied in a string. Numbers must be supplied as numbers without currency formatting.","Failure_to_format_the_data_correctly_can_cause_data_corruption._Please_make_sure_you_make_a_copy_of_the_local_database_before_proceeding.":"Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.","Download_Sample":"Download Sample","Upload_CSV_File":"Upload CSV File","Import":"Import","Edit_Service_Record":"Edit Service Record","Date_service_was_performed":"Date service was performed","Odometer_reading_when_serviced":"Odometer reading when serviced","Description_of_item(s)_serviced(i.e._Oil_Change)":"Description of item(s) serviced(i.e. Oil Change)","Cost_of_the_service":"Cost of the service","Move_To":"Move To","#_of_Repair_Records":"# of Repair Records","Add_Repair_Record":"Add Repair Record","Add_New_Repair_Record":"Add New Repair Record","Date_repair_was_performed":"Date repair was performed","Odometer_reading_when_repaired":"Odometer reading when repaired","Description_of_item(s)_repaired(i.e._Alternator)":"Description of item(s) repaired(i.e. Alternator)","Cost_of_the_repair":"Cost of the repair","Choose_Supplies":"Choose Supplies","Add_Reminder":"Add Reminder","Select_Supplies":"Select Supplies","No_supplies_with_quantities_greater_than_0_is_found.":"No supplies with quantities greater than 0 is found.","Select":"Select","#_of_Upgrade_Records":"# of Upgrade Records","Add_Upgrade_Record":"Add Upgrade Record","Add_New_Upgrade_Record":"Add New Upgrade Record","Date_upgrade/mods_was_installed":"Date upgrade/mods was installed","Odometer_reading_when_upgraded/modded":"Odometer reading when upgraded/modded","Description_of_item(s)_upgraded/modded":"Description of item(s) upgraded/modded","Cost_of_the_upgrade/mods":"Cost of the upgrade/mods","#_of_Gas_Records":"# of Gas Records","Total_Fuel_Consumed":"Total Fuel Consumed","Total_Cost":"Total Cost","Add_Gas_Record":"Add Gas Record","Date_Refueled":"Date Refueled","Consumption":"Consumption","Fuel_Economy":"Fuel Economy","Unit_Cost":"Unit Cost","#_of_Supply_Records":"# of Supply Records","Add_Supply_Record":"Add Supply Record","Part_#":"Part #","Supplier":"Supplier","Quantity":"Quantity","Add_New_Supply_Record":"Add New Supply Record","Date_purchased":"Date purchased","Part_Number":"Part Number","Part_#/Model_#/SKU_#":"Part #/Model #/SKU #","Description_of_the_Part/Supplies":"Description of the Part/Supplies","Supplier/Vendor":"Supplier/Vendor","Part_Supplier":"Part Supplier","Edit_Supply_Record":"Edit Supply Record","Add_New_Service_Record":"Add New Service Record","Supplies_are_requisitioned_immediately_after_the_record_is_created_and_cannot_be_modified._If_you_have_incorrectly_entered_the_amount_you_needed_you_will_need_to_correct_it_in_the_Supplies_tab.":"Supplies are requisitioned immediately after the record is created and cannot be modified. If you have incorrectly entered the amount you needed you will need to correct it in the Supplies tab.","In_Stock":"In Stock","Edit_Repair_Record":"Edit Repair Record","Edit_Upgrade_Record":"Edit Upgrade Record","Save_Vehicle":"Save Vehicle","Add_New_Gas_Record":"Add New Gas Record","Date_refueled":"Date refueled","Odometer_Reading":"Odometer Reading","Odometer_reading_when_refueled":"Odometer reading when refueled","Fuel_Consumption":"Fuel Consumption","Amount_of_gas_refueled":"Amount of gas refueled","Is_Filled_To_Full":"Is Filled To Full","Missed_Fuel_Up(Skip_MPG_Calculation)":"Missed Fuel Up(Skip MPG Calculation)","Cost_of_gas_refueled":"Cost of gas refueled","Unit":"Unit","#_of_Tax_Records":"# of Tax Records","Add_Tax_Record":"Add Tax Record","Add_New_Tax_Record":"Add New Tax Record","Date_tax_was_paid":"Date tax was paid","Description_of_tax_paid(i.e._Registration)":"Description of tax paid(i.e. Registration)","Cost_of_tax_paid":"Cost of tax paid","Is_Recurring":"Is Recurring","Month":"Month","1_Month":"1 Month","3_Months":"3 Months","6_Months":"6 Months","1_Year":"1 Year","2_Years":"2 Years","3_Years":"3 Years","5_Years":"5 Years","Edit_Tax_Record":"Edit Tax Record","#_of_Notes":"# of Notes","Add_Note":"Add Note","Note":"Note","Add_New_Note":"Add New Note","Pinned":"Pinned","Description_of_the_note":"Description of the note","Min_Fuel_Economy":"Min Fuel Economy","Max_Fuel_Economy":"Max Fuel Economy","Edit_Gas_Record":"Edit Gas Record","#_of_Plan_Records":"# of Plan Records","Add_Plan_Record":"Add Plan Record","Planned":"Planned","Doing":"Doing","Testing":"Testing","Done":"Done","Add_New_Plan_Record":"Add New Plan Record","Describe_the_Plan":"Describe the Plan","Cost_of_the_Plan":"Cost of the Plan","Priority":"Priority","Critical":"Critical","Normal":"Normal","Low":"Low","Current_Stage":"Current Stage","#_of_Reminders":"# of Reminders","Urgency":"Urgency","Metric":"Metric","Add_New_Reminder":"Add New Reminder","Reminder_Description":"Reminder Description","Remind_me_on":"Remind me on","Future_Date":"Future Date","Future_Odometer_Reading":"Future Odometer Reading","Whichever_comes_first":"Whichever comes first","Other":"Other","Edit_Reminder":"Edit Reminder","Replace_picture(optional)":"Replace picture(optional)","Language":"Language","Manage_Languages":"Manage Languages","Upload":"Upload","Tokens":"Tokens","Generate_User_Token":"Generate User Token","Auto_Notify(via_Email)":"Auto Notify(via Email)","Token":"Token","Issued_To":"Issued To","Users":"Users","Email":"Email","Is_Admin":"Is Admin","An_error_has_occurred,_please_try_again_later":"An error has occurred, please try again later","Edit_Note":"Edit Note","Password":"Password","Remember_Me":"Remember Me","Login":"Login","Forgot_Password":"Forgot Password","Register":"Register","Request":"Request","I_Have_a_Token":"I Have a Token","Back_to_Login":"Back to Login","Email_Address":"Email Address","New_Password":"New Password","Reset_Password":"Reset Password","No_data_found_or_all_records_have_zero_sums,_insert_records_with_non-zero_sums_to_see_visualizations_here.":"No data found or all records have zero sums, insert records with non-zero sums to see visualizations here.","Save_as_Template":"Save as Template","View_Templates":"View Templates","Select_Template":"Select Template","No_templates_are_found.":"No templates are found.","Use":"Use","Edit_Plan_Record":"Edit Plan Record","Date_Created":"Date Created","Last_Modified":"Last Modified","Shop_Supplies":"Shop Supplies","Uploaded_Documents":"Uploaded Documents","Upload_more_documents":"Upload more documents","Database_Migration":"Database Migration","Instructions":"Instructions","To_Postgres":"To Postgres","From_Postgres":"From Postgres","Import_To_Postgres":"Import To Postgres","Export_From_Postgres":"Export From Postgres","Create":"Create","Manage_Extra_Fields":"Manage Extra Fields","Add/Remove_Extra_Fields":"Add/Remove Extra Fields","Name":"Name","Required":"Required","Add_New_Field":"Add New Field","Close":"Close","Calendar":"Calendar","View_Reminder":"View Reminder","Mark_as_Done":"Mark as Done","Login_via":"Login via","Distance_Traveled_by_Month":"Distance Traveled by Month","Expenses_and_Distance_Traveled_by_Month":"Expenses and Distance Traveled by Month","Select_All":"Select All","Supply_Requisition_History":"Supply Requisition History","No_supply_requisitions_in_history":"No supply requisitions in history","Plan":"Plan","Deselect_All":"Deselect All","Duplicate":"Duplicate","Toggle_Pin":"Toggle Pin","Pin":"Pin","Unpin":"Unpin","Profile":"Profile","Update_Profile":"Update Profile","Account_Username":"Account Username","Send_Token":"Send Token","Update":"Update","Show_Extra_Field_Columns":"Show Extra Field Columns","Enabling_this_may_cause_performance_issues":"Enabling this may cause performance issues","Visible_Columns":"Visible Columns","Edit_Multiple":"Edit Multiple","Edit_Multiple_Records":"Edit Multiple Records","(multiple)":"(multiple)","Tags(use_---_to_clear_all_existing_tags)":"Tags(use --- to clear all existing tags)","Notes(use_---_to_clear_all_existing_notes)":"Notes(use --- to clear all existing notes)","Edit":"Edit","Search":"Search","Delta":"Delta","Vehicle":"Vehicle","Select_Reminder":"Select Reminder","Purchased_Date(optional)":"Purchased Date(optional)","Purchased_Date":"Purchased Date","Sold_Date(optional)":"Sold Date(optional)","Sold_Date":"Sold Date","SOLD":"SOLD","Days":"Days","Statistics":"Statistics","Hide_Sold_Vehicles":"Hide Sold Vehicles","Server-wide_Settings":"Server-wide Settings","Extra_Fields":"Extra Fields","Version":"Version","Configure_Reminder_Urgency_Thresholds":"Configure Reminder Urgency Thresholds","Urgent(Days)":"Urgent(Days)","Very_Urgent(Days)":"Very Urgent(Days)","Urgent(Distance)":"Urgent(Distance)","Very_Urgent(Distance)":"Very Urgent(Distance)","Save":"Save","Initial_Odometer":"Initial Odometer","Distance":"Distance","Initial_Odometer_reading":"Initial Odometer reading","Total_Distance":"Total Distance","Recalculate_Distance":"Recalculate Distance","Edit_Multiple_Odometer_Records":"Edit Multiple Odometer Records","Odometer_Adjustments":"Odometer Adjustments","Odometer_Multiplier":"Odometer Multiplier","Odometer_Difference":"Odometer Difference","Adjust_Odometer":"Adjust Odometer","Edit_Multiple_Gas_Records":"Edit Multiple Gas Records","Multiple":"Multiple","Copy_Attachments":"Copy Attachments","Purchased_Price(optional)":"Purchased Price(optional)","Purchased_Price":"Purchased Price","Sold_Price(optional)":"Sold Price(optional)","Sold_Price":"Sold Price","Purchase/Sold_Information(optional)":"Purchase/Sold Information(optional)","Electric":"Electric","Depreciation":"Depreciation","day":"day","Appreciation":"Appreciation","Search_by_Keyword(Case_Sensitive)":"Search by Keyword(Case Sensitive)","Incremental_Search":"Incremental Search","Unsaved_Changes":"Unsaved Changes","Edit_Plan_Record_Template":"Edit Plan Record Template","No_Data_Found":"No Data Found","Sponsors":"Sponsors","All_Time":"All Time","Metrics":"Metrics","gallons":"gallons","miles":"miles","liters":"liters","kilometers":"kilometers","Fuel_Type":"Fuel Type","Diesel":"Diesel","Documents_Pending_Upload":"Documents Pending Upload","Vehicle_Cost_Breakdown":"Vehicle Cost Breakdown","Cost_Per_Day":"Cost Per Day","Cost_Per_Mile":"Cost Per Mile","Cost_Per_Kilometer":"Cost Per Kilometer","Cost_Per_Hour":"Cost Per Hour","Dashboard_Metrics":"Dashboard Metrics","Last_Odometer":"Last Odometer","Total_Cost_/_Total_Distance_Driven":"Total Cost / Total Distance Driven","Use_Custom_Thresholds":"Use Custom Thresholds","Disable_Registration":"Disable Registration","Default_Reminder_Email":"Default Reminder Email","Default_Email_for_Reminder":"Default Email for Reminder","Enable_OIDC_for_Root_User":"Enable OIDC for Root User","Adaptive_Color_Mode":"Adaptive Color Mode","Uses_the_Default_Reminder_Email_for_OIDC_Auth":"Uses the Default Reminder Email for OIDC Auth","Odometer_Optional":"Odometer Optional","Manage_Tokens":"Manage Tokens","Generate":"Generate","Notify":"Notify","Start_Recording":"Start Recording","Stop_Recording":"Stop Recording","Current_Odometer":"Current Odometer","Experimental_Feature_-_Do_not_exit_or_minimize_this_app_when_recording._Verify_all_starting_and_ending_odometers._Accuracy_subject_to_hardware_limitations.":"Experimental Feature - Do not exit or minimize this app when recording. Verify all starting and ending odometers. Accuracy subject to hardware limitations.","Identifier":"Identifier","Translation_Editor":"Translation Editor","Save_Translation":"Save Translation","Export_Translation":"Export Translation","Get_Translations":"Get Translations","Available_Translations":"Available Translations","Download_All_Translations":"Download All Translations","Reorder_Tabs":"Reorder Tabs","Reset_Tab_Order":"Reset Tab Order","Save_Tab_Order":"Save Tab Order","Upcoming_Reminder":"Upcoming Reminder","Plans":"Plans","No_records_available_to_display":"No records available to display"} \ No newline at end of file diff --git a/wwwroot/lib/masonry/masonry.min.js b/wwwroot/lib/masonry/masonry.min.js new file mode 100644 index 0000000..53386ae --- /dev/null +++ b/wwwroot/lib/masonry/masonry.min.js @@ -0,0 +1,9 @@ +/*! + * Masonry PACKAGED v4.2.2 + * Cascading grid layout library + * https://masonry.desandro.com + * MIT License + * by David DeSandro + */ + +!function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,r,a){function h(t,e,n){var o,r="$()."+i+'("'+e+'")';return t.each(function(t,h){var u=a.data(h,i);if(!u)return void s(i+" not initialized. Cannot call methods, i.e. "+r);var d=u[e];if(!d||"_"==e.charAt(0))return void s(r+" is not a valid method");var l=d.apply(u,n);o=void 0===o?l:o}),void 0!==o?o:t}function u(t,e){t.each(function(t,n){var o=a.data(n,i);o?(o.option(e),o._init()):(o=new r(n,e),a.data(n,i,o))})}a=a||e||t.jQuery,a&&(r.prototype.option||(r.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=o.call(arguments,1);return h(this,t,e)}return u(this,t),this},n(a))}function n(t){!t||t&&t.bridget||(t.bridget=i)}var o=Array.prototype.slice,r=t.console,s="undefined"==typeof r?function(){}:function(t){r.error(t)};return n(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||{};return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var n=this._onceEvents&&this._onceEvents[t],o=0;oe;e++){var i=h[e];t[i]=0}return t}function n(t){var e=getComputedStyle(t);return e||a("Style returned "+e+". Are you running this code in a hidden iframe on Firefox? See https://bit.ly/getsizebug1"),e}function o(){if(!d){d=!0;var e=document.createElement("div");e.style.width="200px",e.style.padding="1px 2px 3px 4px",e.style.borderStyle="solid",e.style.borderWidth="1px 2px 3px 4px",e.style.boxSizing="border-box";var i=document.body||document.documentElement;i.appendChild(e);var o=n(e);s=200==Math.round(t(o.width)),r.isBoxSizeOuter=s,i.removeChild(e)}}function r(e){if(o(),"string"==typeof e&&(e=document.querySelector(e)),e&&"object"==typeof e&&e.nodeType){var r=n(e);if("none"==r.display)return i();var a={};a.width=e.offsetWidth,a.height=e.offsetHeight;for(var d=a.isBorderBox="border-box"==r.boxSizing,l=0;u>l;l++){var c=h[l],f=r[c],m=parseFloat(f);a[c]=isNaN(m)?0:m}var p=a.paddingLeft+a.paddingRight,g=a.paddingTop+a.paddingBottom,y=a.marginLeft+a.marginRight,v=a.marginTop+a.marginBottom,_=a.borderLeftWidth+a.borderRightWidth,z=a.borderTopWidth+a.borderBottomWidth,E=d&&s,b=t(r.width);b!==!1&&(a.width=b+(E?0:p+_));var x=t(r.height);return x!==!1&&(a.height=x+(E?0:g+z)),a.innerWidth=a.width-(p+_),a.innerHeight=a.height-(g+z),a.outerWidth=a.width+y,a.outerHeight=a.height+v,a}}var s,a="undefined"==typeof console?e:function(t){console.error(t)},h=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"],u=h.length,d=!1;return r}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("desandro-matches-selector/matches-selector",e):"object"==typeof module&&module.exports?module.exports=e():t.matchesSelector=e()}(window,function(){"use strict";var t=function(){var t=window.Element.prototype;if(t.matches)return"matches";if(t.matchesSelector)return"matchesSelector";for(var e=["webkit","moz","ms","o"],i=0;is?"round":"floor";r=Math[a](r),this.cols=Math.max(r,1)},n.getContainerWidth=function(){var t=this._getOption("fitWidth"),i=t?this.element.parentNode:this.element,n=e(i);this.containerWidth=n&&n.innerWidth},n._getItemLayoutPosition=function(t){t.getSize();var e=t.size.outerWidth%this.columnWidth,i=e&&1>e?"round":"ceil",n=Math[i](t.size.outerWidth/this.columnWidth);n=Math.min(n,this.cols);for(var o=this.options.horizontalOrder?"_getHorizontalColPosition":"_getTopColPosition",r=this[o](n,t),s={x:this.columnWidth*r.col,y:r.y},a=r.y+t.size.outerHeight,h=n+r.col,u=r.col;h>u;u++)this.colYs[u]=a;return s},n._getTopColPosition=function(t){var e=this._getTopColGroup(t),i=Math.min.apply(Math,e);return{col:e.indexOf(i),y:i}},n._getTopColGroup=function(t){if(2>t)return this.colYs;for(var e=[],i=this.cols+1-t,n=0;i>n;n++)e[n]=this._getColGroupY(n,t);return e},n._getColGroupY=function(t,e){if(2>e)return this.colYs[t];var i=this.colYs.slice(t,t+e);return Math.max.apply(Math,i)},n._getHorizontalColPosition=function(t,e){var i=this.horizontalColIndex%this.cols,n=t>1&&i+t>this.cols;i=n?0:i;var o=e.size.outerWidth&&e.size.outerHeight;return this.horizontalColIndex=o?i+t:this.horizontalColIndex,{col:i,y:this._getColGroupY(i,t)}},n._manageStamp=function(t){var i=e(t),n=this._getElementOffset(t),o=this._getOption("originLeft"),r=o?n.left:n.right,s=r+i.outerWidth,a=Math.floor(r/this.columnWidth);a=Math.max(0,a);var h=Math.floor(s/this.columnWidth);h-=s%this.columnWidth?0:1,h=Math.min(this.cols-1,h);for(var u=this._getOption("originTop"),d=(u?n.top:n.bottom)+i.outerHeight,l=a;h>=l;l++)this.colYs[l]=Math.max(d,this.colYs[l])},n._getContainerSize=function(){this.maxY=Math.max.apply(Math,this.colYs);var t={height:this.maxY};return this._getOption("fitWidth")&&(t.width=this._getContainerFitWidth()),t},n._getContainerFitWidth=function(){for(var t=0,e=this.cols;--e&&0===this.colYs[e];)t++;return(this.cols-t)*this.columnWidth-this.gutter},n.needsResizeLayout=function(){var t=this.containerWidth;return this.getContainerWidth(),t!=this.containerWidth},i}); \ No newline at end of file