Skip to content

Commit

Permalink
Merge pull request #695 from hargata/Hargata/custom.widgets
Browse files Browse the repository at this point in the history
Custom Widgets
  • Loading branch information
hargata authored Nov 4, 2024
2 parents 82634e9 + 5cdc687 commit ada0715
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ config/userConfig.json
CarCareTracker.csproj.user
Properties/launchSettings.json
data/cartracker-log.db
data/widgets.html
21 changes: 21 additions & 0 deletions Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,27 @@ public ActionResult GetVehicleSelector(int vehicleId)
}
return PartialView("_VehicleSelector", vehiclesStored);
}
[Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpGet]
public IActionResult GetCustomWidgetEditor()
{
var customWidgetData = _fileHelper.GetWidgets();
return PartialView("_WidgetEditor", customWidgetData);
}
[Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpPost]
public IActionResult SaveCustomWidgets(string widgetsData)
{
var saveResult = _fileHelper.SaveWidgets(widgetsData);
return Json(saveResult);
}
[Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpPost]
public IActionResult DeleteCustomWidgets()
{
var deleteResult = _fileHelper.DeleteWidgets();
return Json(deleteResult);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
Expand Down
8 changes: 8 additions & 0 deletions Controllers/Vehicle/ReportController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public IActionResult GetReportPartialView(int vehicleId)
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
var userConfig = _config.GetUserConfig(User);
var viewModel = new ReportViewModel();
//check if custom widgets are configured
viewModel.CustomWidgetsConfigured = _fileHelper.WidgetsExist();
//get totalCostMakeUp
viewModel.CostMakeUpForVehicle = new CostMakeUpForVehicle
{
Expand Down Expand Up @@ -528,5 +530,11 @@ public IActionResult GetCostByMonthByVehicle(int vehicleId, List<ImportMode> sel
}).ToList();
return PartialView("_GasCostByMonthReport", groupedRecord);
}
[HttpGet]
public IActionResult GetAdditionalWidgets()
{
var widgets = _fileHelper.GetWidgets();
return PartialView("_ReportWidgets", widgets);
}
}
}
76 changes: 76 additions & 0 deletions Helper/FileHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public interface IFileHelper
int ClearTempFolder();
int ClearUnlinkedThumbnails(List<string> linkedImages);
int ClearUnlinkedDocuments(List<string> linkedDocuments);
string GetWidgets();
bool WidgetsExist();
bool SaveWidgets(string widgetsData);
bool DeleteWidgets();
}
public class FileHelper : IFileHelper
{
Expand Down Expand Up @@ -100,6 +104,7 @@ public bool RestoreBackup(string fileName, bool clearExisting = false)
var documentPath = Path.Combine(tempPath, "documents");
var translationPath = Path.Combine(tempPath, "translations");
var dataPath = Path.Combine(tempPath, StaticHelper.DbName);
var widgetPath = Path.Combine(tempPath, StaticHelper.AdditionalWidgetsPath);
var configPath = Path.Combine(tempPath, StaticHelper.UserConfigPath);
if (Directory.Exists(imagePath))
{
Expand Down Expand Up @@ -174,6 +179,10 @@ public bool RestoreBackup(string fileName, bool clearExisting = false)
//data path will always exist as it is created on startup if not.
File.Move(dataPath, StaticHelper.DbName, true);
}
if (File.Exists(widgetPath))
{
File.Move(widgetPath, StaticHelper.AdditionalWidgetsPath, true);
}
if (File.Exists(configPath))
{
//check if config folder exists.
Expand Down Expand Up @@ -223,6 +232,7 @@ public string MakeBackup()
var documentPath = Path.Combine(_webEnv.WebRootPath, "documents");
var translationPath = Path.Combine(_webEnv.WebRootPath, "translations");
var dataPath = StaticHelper.DbName;
var widgetPath = StaticHelper.AdditionalWidgetsPath;
var configPath = StaticHelper.UserConfigPath;
if (!Directory.Exists(tempPath))
Directory.CreateDirectory(tempPath);
Expand Down Expand Up @@ -262,6 +272,12 @@ public string MakeBackup()
Directory.CreateDirectory(newPath);
File.Copy(dataPath, $"{newPath}/{Path.GetFileName(dataPath)}");
}
if (File.Exists(widgetPath))
{
var newPath = Path.Combine(tempPath, "data");
Directory.CreateDirectory(newPath);
File.Copy(widgetPath, $"{newPath}/{Path.GetFileName(widgetPath)}");
}
if (File.Exists(configPath))
{
var newPath = Path.Combine(tempPath, "config");
Expand Down Expand Up @@ -323,12 +339,20 @@ public int ClearTempFolder()
var tempPath = GetFullFilePath("temp", false);
if (Directory.Exists(tempPath))
{
//delete files
var files = Directory.GetFiles(tempPath);
foreach (var file in files)
{
File.Delete(file);
filesDeleted++;
}
//delete folders
var folders = Directory.GetDirectories(tempPath);
foreach(var folder in folders)
{
Directory.Delete(folder, true);
filesDeleted++;
}
}
return filesDeleted;
}
Expand Down Expand Up @@ -368,5 +392,57 @@ public int ClearUnlinkedDocuments(List<string> linkedDocuments)
}
return filesDeleted;
}
public string GetWidgets()
{
if (File.Exists(StaticHelper.AdditionalWidgetsPath))
{
try
{
//read file
var widgets = File.ReadAllText(StaticHelper.AdditionalWidgetsPath);
return widgets;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return string.Empty;
}
}
return string.Empty;
}
public bool WidgetsExist()
{
return File.Exists(StaticHelper.AdditionalWidgetsPath);
}
public bool SaveWidgets(string widgetsData)
{
try
{
//Delete Widgets if exists
DeleteWidgets();
File.WriteAllText(StaticHelper.AdditionalWidgetsPath, widgetsData);
return true;
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteWidgets()
{
try
{
if (File.Exists(StaticHelper.AdditionalWidgetsPath))
{
File.Delete(StaticHelper.AdditionalWidgetsPath);
}
return true;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}
1 change: 1 addition & 0 deletions Helper/StaticHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static class StaticHelper
public static string VersionNumber = "1.4.0";
public static string DbName = "data/cartracker.db";
public static string UserConfigPath = "config/userConfig.json";
public static string AdditionalWidgetsPath = "data/widgets.html";
public static string GenericErrorMessage = "An error occurred, please try again later";
public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt";
public static string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx";
Expand Down
1 change: 1 addition & 0 deletions Models/Report/ReportViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public class ReportViewModel
public ReminderMakeUpForVehicle ReminderMakeUpForVehicle { get; set; } = new ReminderMakeUpForVehicle();
public List<int> Years { get; set; } = new List<int>();
public List<UserCollaborator> Collaborators { get; set; } = new List<UserCollaborator>();
public bool CustomWidgetsConfigured { get; set; } = false;
}
}
6 changes: 6 additions & 0 deletions Views/Home/_Settings.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,12 @@
</div>
</div>
</div>
<div class="modal fade" data-bs-focus="false" id="customWidgetModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="customWidgetModalContent">
</div>
</div>
</div>
<div class="modal fade" data-bs-focus="false" id="tabReorderModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="tabReorderModalContent">
Expand Down
28 changes: 28 additions & 0 deletions Views/Home/_WidgetEditor.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model string
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
<div class="modal-header">
<h5 class="modal-title" id="widgetEditorModalLabel">@translator.Translate(userLanguage, "Custom Widgets Editor")</h5>
<button type="button" class="btn-close" onclick="hideCustomWidgets()" aria-label="Close"></button>
</div>
<div class="modal-body" onkeydown="handleEnter(this)">
<form class="form-inline">
<div class="form-group" style="height:50vh; overflow-x:hidden; overflow-y:auto;">
<div class="row">
<div class="col-12" style="height:48vh;">
<textarea id="widgetEditor" style="width:100%; height:100%;">@Model</textarea>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger me-auto" onclick="deleteCustomWidgets()">@translator.Translate(userLanguage, "Delete")</button>
<button type="button" class="btn btn-secondary" onclick="hideCustomWidgets()">@translator.Translate(userLanguage, "Cancel")</button>
<button type="button" class="btn btn-primary" onclick="saveCustomWidgets()">@translator.Translate(userLanguage, "Save")</button>
</div>
15 changes: 15 additions & 0 deletions Views/Vehicle/_Report.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
<div class="d-grid">
<button onclick="exportAttachments()" class="btn btn-secondary btn-md mt-1 mb-1">@translator.Translate(userLanguage, "Export Attachments")<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button>
</div>
@if (Model.CustomWidgetsConfigured)
{
<div class="d-grid">
<button onclick="loadCustomWidgets()" class="btn btn-secondary btn-md mt-1 mb-1">@translator.Translate(userLanguage, "Additional Widgets")<i class="bi ms-2 bi-box-arrow-in-up-right"></i></button>
</div>
}
</div>
</div>
</div>
Expand Down Expand Up @@ -153,6 +159,15 @@
</div>
</div>
</div>
@if (Model.CustomWidgetsConfigured)
{
<div class="modal fade" data-bs-focus="false" id="vehicleCustomWidgetsModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="vehicleCustomWidgetsModalContent">
</div>
</div>
</div>
}
<div id="vehicleHistoryReport" class="showOnPrint"></div>

<script>
Expand Down
2 changes: 2 additions & 0 deletions Views/Vehicle/_ReportWidgets.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@model string
@Html.Raw(Model)
2 changes: 1 addition & 1 deletion wwwroot/defaults/en_US.json

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions wwwroot/js/reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,13 @@ function loadGlobalSearchResult(recordId, recordType) {
waitForElement('#planRecordModalContent', showEditPlanRecordModal, recordId);
break;
}
}
function loadCustomWidgets() {
$.get('/Vehicle/GetAdditionalWidgets', function (data) {
$("#vehicleCustomWidgetsModalContent").html(data);
$("#vehicleCustomWidgetsModal").modal('show');
})
}
function hideCustomWidgetsModal() {
$("#vehicleCustomWidgetsModal").modal('hide');
}
55 changes: 55 additions & 0 deletions wwwroot/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,4 +351,59 @@ function resetTabOrder() {
$(elem).css('order', -1);
})
updateSettings();
}

function hideCustomWidgets() {
$("#customWidgetModal").modal('hide');
}
function saveCustomWidgets() {
$.post('/Home/SaveCustomWidgets', { widgetsData: $("#widgetEditor").val() }, function (data) {
if (data) {
successToast("Custom Widgets Saved!");
updateSettings();
} else {
errorToast(genericErrorMessage());
}
})
}
function deleteCustomWidgets() {
$.post('/Home/DeleteCustomWidgets', function (data) {
if (data) {
successToast("Custom Widgets Deleted!");
updateSettings();
} else {
errorToast(genericErrorMessage());
}
})
}
function showCustomWidgets() {
Swal.fire({
title: 'Warning',
icon: "warning",
html: `
<span>
You are about to use the Custom Widgets Editor, this is a developer-focused feature that can lead to security vulnerabilities if you don't understand what you're doing.
<br />Zero support will be provided from the developer(s) of LubeLogger regarding Custom Widgets, Read the Documentation.
<br />By proceeding, you acknowledge that you are solely responsible for all consequences from utilizing the Custom Widgets Editor.
<br />To proceed, enter 'acknowledge' into the text field below.
</span>
<input type="text" id="inputAcknowledge" class="swal2-input" placeholder="acknowledge" onkeydown="handleSwalEnter(event)">
`,
confirmButtonText: 'Proceed',
focusConfirm: false,
preConfirm: () => {
const userAcknowledge = $("#inputAcknowledge").val();
if (!userAcknowledge || userAcknowledge != 'acknowledge') {
Swal.showValidationMessage(`Please acknowledge before proceeding.`)
}
return { userAcknowledge }
},
}).then(function (result) {
if (result.isConfirmed) {
$.get('/Home/GetCustomWidgetEditor', function (data) {
$("#customWidgetModalContent").html(data);
$("#customWidgetModal").modal('show');
});
}
});
}

0 comments on commit ada0715

Please sign in to comment.