v1.2.10.5

This commit is contained in:
2023-02-07 20:05:38 +00:00
parent aa2f350a35
commit ca29099508
19 changed files with 1004 additions and 14 deletions
@@ -14,6 +14,8 @@ using System.Threading.Tasks;
namespace Saxonite.Net.Core.Web.Admin.Controllers
{
//=======================================================================
// Sport Controller - Ajax requests.
//=======================================================================
partial class SportController
{
@@ -0,0 +1,351 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Core.Web.Admin.Models;
using Saxonite.Net.Core.Web.Admin.Models.Support;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Bus.Support;
using System;
using System.Collections.Generic;
using System.Linq;
using Sarand.Net.Standard.Base.Utils;
namespace Saxonite.Net.Core.Web.Admin.Controllers.Support
{
//=======================================================================
// UserReport Controller - Ajax requests.
//=======================================================================
partial class Controller_UserReport
{
//-------------------------------------------------------------------
// UserReport data.
private class UserReportListData : AjaxResponse_Data.ItemData_Base
{
// Account Id only populated while account names are being queried, then nulled.
public SysId UserAccountId { get; set; }
public String UserDisplayName { get; set; }
public String ReportTypeCode { get; set; }
public String ReportTypeDesc { get; set; }
public String Title { get; set; }
public String RecordedOnDisp { get; set; }
}
private class UserReportItemData : UserReportListData
{
public String ReportType { get; set; }
public String Report { get; set; }
public String RecordedOnForm { get; set; }
}
private void PopulateUserReportResponseListData(SaxModel_Admin model, SaxUserReport userReport, SaxUserAccount userAccount, UserReportListData data)
{
data.Id = SysId.ToString(userReport.Id);
data.UserDisplayName = userAccount.GetDisplayName();
data.ReportTypeCode = UserReportTypeCodes.GetCodeForType(userReport.ReportType);
data.ReportTypeDesc = model.Localiser.GetUserReportTypeCaption(userReport.ReportType);
data.Title = userReport.Title;
data.RecordedOnDisp = model.FormatDateForDisplay(userReport.RecordedOn);
data.StatusCode = userReport.StatusCode;
data.StatusDesc = userReport.StatusDesc;
}
private void PopulateUserReportResponseItemData(Model_UserReport model, SaxUserReport userReport, SaxUserAccount userAccount, UserReportItemData data)
{
PopulateUserReportResponseListData(model, userReport, userAccount, data);
data.Report = userReport.Report;
data.RecordedOnForm = model.FormatDateForForm(userReport.RecordedOn);
}
//-------------------------------------------------------------------
// Ajax - User Report list.
//-------------------------------------------------------------------
private class AjaxResponse_UserReportList : AjaxResponse_Data
{
// Construction.
public AjaxResponse_UserReportList(SaxModel_Admin model) : base(model) { }
// UserReport list.
public List<UserReportListData> Reports { get; } = new List<UserReportListData>();
// Reference data.
public List<ItemCodeDesc> ReportTypes { get; } = new List<ItemCodeDesc>();
public List<ItemCodeDesc> Statuses { get; } = new List<ItemCodeDesc>();
public String DefaultStatusCode { get; set; }
}
//-------------------------------------------------------------------
[HttpPost]
[Route("UserReport/Ajax/GetList")]
public IActionResult Ajax_GetList(Model_UserReport model)
{
String fn = GetType().Name + ".Ajax_GetList";
String messageTitle = Localiser["caption.user.reports"];
AjaxResponse_UserReportList responseData = new AjaxResponse_UserReportList(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Reference data - report types.
responseData.ReportTypes.Add(new AjaxResponse_Data.ItemCodeDesc());
List<Sax.UserReportType> validReportTypes = new List<Sax.UserReportType>(EnumUtil.GetValues<Sax.UserReportType>());
foreach (TypeCodeDesc reportType in UserReportTypeCodes)
{
if (!validReportTypes.Contains((Sax.UserReportType)reportType.Type)) continue;
responseData.ReportTypes.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = reportType.Code, Desc = Localiser.GetUserReportTypeCaption((Sax.UserReportType)reportType.Type) });
}
// Reference data - statuses.
foreach (SaStatus status in SaxUserReport.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
responseData.Statuses.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = SacsSystem.GetStatusCode(status), Desc = Localiser.GetStatusCaption(status) });
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxUserReport.DefaultStatus);
// Item filter.
SaxUserReport.Params prmUserReport = new SaxUserReport.Params();
prmUserReport.UserReportFilter = model.Filter.Report;
prmUserReport.StatusCat = SaxUserReport.StatusCat.NotDeleted;
model.Paging.ItemTotal = (ulong)SupportMgr.GetUserReportCount(prmUserReport);
model.PopulatePagingTo(prmUserReport.ResultsPaging);
// Item columns.
ColumnDfn colId = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Id);
ColumnDfn colUserAccountId = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.UserAccountId);
ColumnDfn colReportType = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.ReportType);
ColumnDfn colTitle = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Title);
ColumnDfn colRecordedOn = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.RecordedOn);
ColumnDfn colStatus = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Status);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
colId, colUserAccountId, colReportType, colTitle,
colRecordedOn, colStatus
};
// Sort order.
prmUserReport.SortColumns.Add(colRecordedOn);
prmUserReport.SortColumns.Last().SortAscending = false;
prmUserReport.SortColumns.Add(colId);
prmUserReport.SortColumns.Last().SortAscending = false;
// User account details must be queried separately - different database!
HashSet<SysId> userAccountIds = new HashSet<SysId>();
// Query items.
using (DbResultSet resultSet = SupportMgr.ExecuteUserReportQuery(columns, prmUserReport))
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
SysId userAccountId = new SysId(values.GetLong(colUserAccountId.DataName));
userAccountIds.AddId(userAccountId);
Sax.UserReportType reportType = (Sax.UserReportType)values.GetLong(colReportType.DataName);
UserReportListData userReportData = new UserReportListData()
{
Id = values.GetString(colId.DataName),
UserAccountId = userAccountId,
ReportTypeCode = UserReportTypeCodes.GetCodeForType(reportType),
ReportTypeDesc = model.Localiser.GetUserReportTypeCaption(reportType),
Title = values.GetString(colTitle.DataName),
RecordedOnDisp = model.FormatDateForDisplay(values.GetDate(colRecordedOn.DataName)),
StatusCode = values.GetString(colStatus.DataName),
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
};
responseData.Reports.Add(userReportData);
}
}
if (model.Paging.IsPaged)
model.Paging.ItemCount = (ushort)responseData.Reports.Count;
// Query and populate User Account details.
if (userAccountIds.Any())
{
// User Account columns.
ColumnDfn colUserAccount_Id = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Id);
ColumnDfn colUserAccount_Title = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Title);
ColumnDfn colUserAccount_FirstName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.FirstName);
ColumnDfn colUserAccount_LastName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastName);
List<ColumnDfn> userAccountCols = new List<ColumnDfn>() { colUserAccount_Id, colUserAccount_Title, colUserAccount_FirstName, colUserAccount_LastName };
// User Account filter.
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
prmUserAccount.IdsIncluded.AddRange(userAccountIds);
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.Any;
// Query user accounts and populate properties to report list.
using (DbResultSet resultSet = AccountMgr.ExecuteUserAccountQuery(userAccountCols, prmUserAccount))
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
SysId userAccountId = new SysId(values.GetLong(colUserAccount_Id.DataName));
String title = values.GetString(colUserAccount_Title.DataName);
String firstName = values.GetString(colUserAccount_FirstName.DataName);
String lastName = values.GetString(colUserAccount_LastName.DataName);
foreach (UserReportListData userReportData in responseData.Reports.FindAll(item => SysId.InvalidOnNull(item.UserAccountId).Equals(userAccountId)))
{
userReportData.UserDisplayName = SaxUserAccount.GetDisplayName(title, firstName, lastName);
userReportData.UserAccountId = null;
}
}
}
// Clear any remaining User Account Ids.
foreach (UserReportListData userReportData in responseData.Reports.FindAll(item => item.UserAccountId != null))
userReportData.UserAccountId = null;
}
// Complete response.
responseData.SetPaging(model);
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Ajax - User Report properties.
//-------------------------------------------------------------------
private class AjaxResponse_UserReport : AjaxResponse_Data
{
// Construction.
public AjaxResponse_UserReport(SaxModel_Admin model) : base(model) { }
// UserReport details.
public UserReportItemData Report { get; } = new UserReportItemData();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("UserReport/Ajax/GetItem")]
public IActionResult Ajax_GetItem(Model_UserReport model)
{
String fn = GetType().Name + ".Ajax_GetItem";
String messageTitle = Localiser["caption.user.report"];
AjaxResponse_UserReport responseData = new AjaxResponse_UserReport(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
// Identify item.
SysId userReportId = model.UserReport.Id.ToSysId();
if (!SysId.IsValid(userReportId))
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
SaxUserReport userReport = SupportMgr.GetUserReportById(userReportId);
disposableItems.Add(userReport);
if (userReport == null)
{
SaLogger.Warn(fn + " Failed to retrieve userReport for Id: '" + model.UserReport.Id + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Retrieve user.
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userReport.UserAccountId);
disposableItems.Add(userAccount);
// Construct response.
PopulateUserReportResponseItemData(model, userReport, userAccount, responseData.Report);
}
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Ajax - User Report storage.
//-------------------------------------------------------------------
[HttpPost]
[Route("UserReport/Ajax/StoreItem")]
public IActionResult Ajax_StoreItem(Model_UserReport model)
{
String fn = GetType().Name + ".Ajax_StoreItem";
String messageTitle = Localiser["caption.user.report"];
AjaxResponse_UserReport responseData = new AjaxResponse_UserReport(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
// Validate item properties.
model.ValidateUserReportData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Retrieve existing item.
SysId userReportId = model.UserReport.Id.ToSysId();
if (StringUtil.ToBool(model.UserReport.Exists) && !SysId.IsValid(userReportId))
{
SaLogger.Warn(fn + " Item Id not supplied for existing item.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (!StringUtil.ToBool(model.UserReport.Exists) && SysId.IsValid(userReportId))
{
SaLogger.Warn(fn + " Item Id supplied for new item: '" + model.UserReport.Id + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
SaxUserReport userReport = SupportMgr.GetUserReportById(userReportId);
disposableItems.Add(userReport);
if (userReport == null && SysId.IsValid(userReportId))
{
SaLogger.Warn(fn + " Failed to retrieve userReport for Id: '" + model.UserReport.Id + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Create new item if required.
if (userReport == null)
{
userReport = SupportMgr.CreateUserReport(SessionUserAccountId);
disposableItems.Add(userReport);
userReport.RecordedOn = DateTime.Today;
}
// Populate item properties.
if (model.UserReport.ReportType != null)
userReport.ReportType = model.UserReportType;
if (model.UserReport.Title != null)
userReport.Title = model.UserReport.Title;
if (model.UserReport.Report != null)
userReport.Report = model.UserReport.Report;
if (model.UserReport.Status != null)
userReport.Status = model.UserReportStatus;
// Store item.
if (!SysId.IsValid(userReport.Id))
{
if (!SupportMgr.InsertUserReport(userReport, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert userReport: " + SupportMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + SupportMgr.ErrorStateMessage));
}
}
else
{
if (!SupportMgr.UpdateUserReport(userReport, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update userReport [Id:" + SysId.ToString(userReport.Id) + "]: " + SupportMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + SupportMgr.ErrorStateMessage));
}
}
// Retrieve user.
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userReport.UserAccountId);
disposableItems.Add(userAccount);
// Construct response.
PopulateUserReportResponseItemData(model, userReport, userAccount, responseData.Report);
}
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Saxonite.Net.Core.Web.Admin.Models.Support;
using Saxonite.Net.Core.Web.Base.App;
using System;
namespace Saxonite.Net.Core.Web.Admin.Controllers.Support
{
//=======================================================================
public partial class Controller_UserReport : SaxController_Admin_Support
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public Controller_UserReport(SaxLocaliser localiser, ILogger<HomeController> logger) :
base(localiser, logger)
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// Index page.
[HttpGet]
[Route("UserReport")]
[Route("UserReport/Index")]
public IActionResult Index(String sta)
{
// Validate session.
if (!ValidUserSession)
return RedirectToAction("", "");
// Model.
Model_UserReport model = new Model_UserReport(Localiser);
return View("/Views/UserReport/Index.cshtml", model);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Saxonite.Net.Core.Web.Admin.Models.Support;
using Saxonite.Net.Core.Web.Base.App;
using System;
namespace Saxonite.Net.Core.Web.Admin.Controllers.Support
{
//=======================================================================
public abstract class SaxController_Admin_Support : SaxController_Admin
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Protected construction.
protected SaxController_Admin_Support(SaxLocaliser localiser, ILogger<HomeController> logger) :
base(localiser, logger)
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -25,7 +25,7 @@ namespace Saxonite.Net.Core.Web.Admin.Models
//-------------------------------------------------------------------
// Session.
public SaxSessionData_Admin SessionData_Admin { get { return SessionData as SaxSessionData_Admin; } }
public SysId UserAccountId { get { return SessionData_Admin?.User?.UserAccountId ?? null; } }
public SysId SessionUserAccountId { get { return SessionData_Admin?.User?.UserAccountId ?? null; } }
//-------------------------------------------------------------------
// Reference data.
@@ -0,0 +1,95 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Core.Web.Base.Controllers;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Bus.Support;
using System;
namespace Saxonite.Net.Core.Web.Admin.Models.Support
{
//=======================================================================
public class Model_UserReport : SaxModel_Admin_Support
{
//-------------------------------------------------------------------
// Construction.
public Model_UserReport(SaxLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// User Report list configuration.
public class FilterData
{
public String Report { get; set; }
}
public FilterData Filter { get; } = new FilterData();
//-------------------------------------------------------------------
// Sport properties.
public class UserReportData
{
public String Id { get; set; }
public String Exists { get; set; }
public String ReportType { get; set; }
public String Title { get; set; }
public String Report { get; set; }
public String Status { get; set; }
}
public UserReportData UserReport { get; } = new UserReportData();
public Sax.UserReportType UserReportType{ get { return (Sax.UserReportType)UserReportTypeCodes.GetTypeForCode(UserReport.ReportType); } }
public SaStatus UserReportStatus { get { return SacsSystem.GetStatusForCode(UserReport.Status); } }
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// User Report.
public bool ValidateUserReportData(SaxController_Base.AjaxResponse_Data responseData)
{
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
// Report Type.
String controlName = "UserReportType";
if (UserReport.ReportType != null)
{
if (StringUtil.IsEmpty(UserReport.ReportType))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (UserReportType <= 0)
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
// Report Title.
controlName = "UserReportTitle";
if (UserReport.Title != null)
{
responseData.SetControlValue(controlName, UserReport.Title);
if (StringUtil.IsEmpty(UserReport.Title))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(UserReport.Title) > GetControlMaxLength(SaxDbDfn_Support.ColumnIdx.UserReport_Title))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Support.ColumnIdx.UserReport_Title)]);
}
// Status.
controlName = "UserReportStatus";
if (UserReport.Status != null)
{
if (StringUtil.IsEmpty(UserReport.Status))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SaxUserReport.ValidStatuses.Contains(UserReportStatus))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,21 @@
using Saxonite.Net.Core.Web.Base.App;
namespace Saxonite.Net.Core.Web.Admin.Models.Support
{
//=======================================================================
public class SaxModel_Admin_Support : SaxModel_Admin
{
//-------------------------------------------------------------------
// Protected construction.
protected SaxModel_Admin_Support(SaxLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -156,6 +156,18 @@
<data name="caption.organisations" xml:space="preserve">
<value>Organisations</value>
</data>
<data name="caption.user.report" xml:space="preserve">
<value>User Report</value>
</data>
<data name="caption.user.report.create" xml:space="preserve">
<value>Create User Report</value>
</data>
<data name="caption.user.report.update" xml:space="preserve">
<value>Update User Report</value>
</data>
<data name="caption.user.reports" xml:space="preserve">
<value>User Reports</value>
</data>
<data name="company.name" xml:space="preserve">
<value>Sportierre</value>
</data>
@@ -432,6 +444,9 @@
<data name="label.remove" xml:space="preserve">
<value>Remove</value>
</data>
<data name="label.report" xml:space="preserve">
<value>Report</value>
</data>
<data name="label.roles" xml:space="preserve">
<value>Roles</value>
</data>
@@ -477,6 +492,9 @@
<data name="label.strength" xml:space="preserve">
<value>Strength</value>
</data>
<data name="label.support" xml:space="preserve">
<value>Support</value>
</data>
<data name="label.system" xml:space="preserve">
<value>System</value>
</data>
@@ -118,6 +118,16 @@
}
else
{
<li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.accounts"]
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('UsersOnline');">@Localiser["label.users.online"]</div>
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('User');">@Localiser["user.caption.users"]</div>
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Organisation');">@Localiser["caption.organisations"]</div>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.reference"]
@@ -129,12 +139,10 @@
</li>
<li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.accounts"]
@Localiser["label.support"]
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('UsersOnline');">@Localiser["label.users.online"]</div>
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('User');">@Localiser["user.caption.users"]</div>
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Organisation');">@Localiser["caption.organisations"]</div>
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('UserReport');">@Localiser["caption.user.reports"]</div>
</div>
</li>
<li class="nav-item dropdown">
@@ -0,0 +1,116 @@
@model Model_UserReport
@inject SaxLocaliser Localiser
@{
/* User Report - Index */
ViewData["Title"] = "User Reports";
Model.AdditionalFiles_JS.Add("js/sax-spt-rpt.js");
}
<div class="sax-panel UserReports">
<script type="text/javascript">
sax.lbl.refresh = '@(Localiser.GetJavascriptText("label.refresh"))';
sax.lbl.create = '@(Localiser.GetJavascriptText("label.create"))';
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
</script>
<div class="row">
@* Filter Panel *@
<div class="col-md-4">
<div class="sax-panel-filter mr-md-2">
@* Filter Form *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserReportFilter", @class = "sax-form", @onSubmit = "return false;" }))
{
@* Header - Page caption, paging controls, actions. *@
<div class="sax-header row">
<div class="col"><div class="sax-caption">@Localiser["caption.user.reports"]</div></div>
<div class="fixed row">
<div class="col">
<partial name="~/Views/Common/ResultsPaging.cshtml" />
</div>
<div class="fixed">
@* Burger menu *@
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="sax-content">
<div class="row">
<div class="col-sm-5 sax-label text-left text-sm-right">@Localiser["label.report"]</div>
<div class="col-sm-7">@Html.TextBoxFor(model => model.Filter.Report, new { @id = "ifFilterUserReport", @class = "FilterUserReport", @maxlength = "32" })</div>
</div>
</div>
@* Filter element templates *@
<div class="sax-panel-item-template">
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu UserReportFilter">
<li class="sax-dropdown-item sax-action"><div class="sax-label">XXX</div></li>
</ul>
</div>
}
</div>
</div>
@* Results Panel *@
<div class="col">
<div class="sax-panel-results">
<div class="sax-panel-messages"></div>
<div class="sax-panel-item-list"></div>
@* Element templates *@
<div class="sax-panel-item-template">
@* UserReport item template *@
<div class="sax-panel-item UserReport">
<div class="sax-header row">
<div class="col">
<div class="sax-caption"><div class="sax-action sax-item-update UserReportTitle">UserReport Title</div></div>
</div>
<div class="fixed sax-actions">
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
<div class="sax-content">
<div class="row">
<div class="col-sm-4"><div class="sax-note UserReportRaised"><span class="UserDisplayName"></span>&nbsp;<span class="UserReportRaisedOnDisp"></span></div></div>
<div class="col-sm-4"><div class="sax-note"></div></div>
<div class="col-sm-4 right"><div class="sax-note StatusDesc"></div></div>
</div>
<div class="row">
<div class="col-sm-4"></div>
<div class="col-sm-4"><div class=""></div></div>
</div>
</div>
</div>
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu UserReport">
<li class="sax-dropdown-item sax-action"><div class="sax-label">XXX</div></li>
</ul>
</div>
</div>
</div>
</div>
<partial name="Panel-UserReportDialog.cshtml" />
</div>
@@ -0,0 +1,99 @@
@model Model_UserReport
@inject SaxLocaliser Localiser
@{
/* Support - User Report dialog */
}
<script type="text/javascript">
sax.dlg.title.createUserReport = '@Localiser.GetJavascriptText("caption.user.report.create")';
sax.dlg.title.updateUserReport = '@Localiser.GetJavascriptText("caption.user.report.update")';
</script>
@* User Report Id form. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserReportId", @class = "sax-form" }))
{
@Html.HiddenFor(model => model.UserReport.Id, new { @class = "UserReportId" })
}
@* User Report dialog *@
<div id="dlgUserReport" class="sax-dialog" title="">
<div class="spacer4"></div>
@* User Report form *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserReport", @class = "sax-form", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.UserReport.Id, new { @class = "UserReportId" })
@Html.HiddenFor(model => model.UserReport.Exists, new { @class = "UserReportExists" })
@* User Report Type *@
<div class="sax-form-control UserReportType">
<div class="row">
<div class="col-sm-3">
<div class="sax-label">
<label for="cbUserReportType"><span>@Localiser["label.type"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sax-control">
<select name="UserReport.ReportType" id="cbUserReportType" class="UserReportType sax-select"></select>
</div>
<div class="sax-message"></div>
</div>
</div>
</div>
@* User Report Title *@
<div class="sax-form-control UserReportTitle">
<div class="row">
<div class="col-sm-3">
<div class="sax-label">
<label for="ifUserReportTitle"><span>@Localiser["label.title"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sax-control">
@Html.TextBoxFor(model => model.UserReport.Title, new { @id = "ifUserReportTitle", @class = "UserReportTitle sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Support.ColumnIdx.UserReport_Title) })
</div>
<div class="sax-message"></div>
</div>
</div>
</div>
@* Report *@
<div class="sax-form-control UserReportReport">
<div class="row">
<div class="col-sm-3">
<div class="sax-label">
<label for="ifUserReportReport"><span>@Localiser["label.report"]</span></label>
</div>
</div>
<div class="col-sm">
<div class="sax-control">
@Html.TextAreaFor(model => model.UserReport.Report, new { @id = "ifUserReportReport", @class = "UserReportReport sax-textarea", @rows = 12, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Support.ColumnIdx.UserReport_Report) })
</div>
<div class="sax-message"></div>
</div>
</div>
</div>
@* UserReport Status *@
<div class="sax-form-control UserReportStatus">
<div class="row">
<div class="col-sm-3">
<div class="sax-label">
<label for="cbUserReportStatus"><span>@Localiser["label.status"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sax-control">
<select id="cbUserReportStatus" class="sax-select UserReportStatus" name="UserReport.Status"></select>
</div>
<div class="sax-message"></div>
</div>
</div>
</div>
}
<div class="spacer2"></div>
</div>
@@ -4,4 +4,5 @@
@using Saxonite.Net.Standard.Base.App
@using Saxonite.Net.Core.Web.Base.App
@using Saxonite.Net.Core.Web.Admin.Models
@using Saxonite.Net.Core.Web.Admin.Models.Support
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
+1 -1
View File
@@ -102,7 +102,7 @@
code = code || 'code';
desc = desc || 'desc';
$sel = $($sel).empty();
for (const value of values)
for (const value of values || [])
$sel.append($('<option>').prop('value', value[code]).text(value[desc]));
}
sax.populateSelectCodeDesc = function ($sel, values)
@@ -0,0 +1,199 @@
/*
* Admin - Support - User Report scripts.
*/
(function (win, doc, undef)
{
"use strict";
let sr = sax.SupportUserReport = { $pnl: {}, $frm: {}, $dlg: {}, ajax: {}, data: {} };
let $pnl = sr.$pnl, $frm = sr.$frm, $dlg = sr.$dlg;
//--------------------------------------------------------------
sr.refreshResults = function (delay)
{
if (!sr.awaitingRefreshResponse)
{
$('.sax-burger', $pnl.filter).hide();
var $items = $('.sax-panel-item-list', $pnl.results).fadeOut(200).empty();
$pnl.msgs.hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
}
sr.ajax.refreshResults = sr.ajax.refreshResults || { url: sax.url.base + 'UserReport/Ajax/GetList', formId: 'frmUserReportFilter', callbackFn: sr.doRefreshResults };
sax.doAjaxRequest(sr.ajax.refreshResults, delay || 50);
sr.awaitingRefreshResponse = true;
}
sr.doRefreshResults = function (response)
{
sax.debug('doRefreshResults', response);
delete sr.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
$pnl.msgs.hide().empty();
var $items = $('.sax-panel-item-list', $pnl.results).hide().empty();
sax.refreshPaging(response, '#frmUserReportFilter', sr.refreshResults);
if (!response.success) return;
// Reference data.
sr.data.reportTypes = response.reportTypes;
sr.data.statuses = response.statuses;
sr.data.defaultStatusCode = response.defaultStatusCode;
// Menu.
var $bgr = $('.sax-burger', $pnl.filter).hide();
var $mnu = $('ul.sax-dropdown-menu', $bgr).empty();
$mnu.append(sr.getFilterMenuOption(sax.lbl.refresh, function () { sr.refreshResults(); }, 'sax-refresh'));
$mnu.append(sr.getFilterMenuOption(sax.lbl.create, function () { sr.createItem(); }, 'sax-add'));
$bgr.toggle(!!$('.sax-dropdown-item', $mnu).length);
// Items.
var items = response.reports;
if (!items.length)
return $pnl.msgs.append($('<div class="sax-message">' + sax.msg.dataNoneFound + '</div>')).fadeIn(500);
for (let itemIdx = 0; itemIdx < items.length; itemIdx++)
$items.append(sr.populateItem(sr.getItemTemplate(), items[itemIdx]));
$items.fadeIn(50);
}
sr.populateItem = function ($item, item)
{
if (!item) return;
$('.UserReportType', $item).text(item.reportTypeDesc);
$('.UserReportTitle', $item).text(item.title);
$('.UserDisplayName', $item).text(item.userDisplayName);
$('.UserReportRaisedOnDisp', $item).text(item.recordedOnDisp);
$('.StatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase());
$('.sax-caption .sax-action',$item).toggleClass('sax-action', !item.deleted);
let $mnu = $('ul.sax-dropdown-menu', $item).empty();
if (!item.deleted)
{
$mnu.append(sr.getItemMenuOption(sax.lbl.edit, function () { sr.updateItem(item,$item) }, 'sax-edit'));
$('.sax-header .sax-action.sax-item-update', $item).off('click').on('click', function () { sr.updateItem(item, $item) });
$item.off('dblclick').on('dblclick', function () { sr.updateItem(item, $item) });
}
$('.sax-burger', $item).toggle(!!$('.sax-dropdown-item', $mnu).length);
$('.sax-panel-messages', $pnl.results).hide().empty();
return $item;
}
//--------------------------------------------------------------
sr.getFilterDropdownTemplate = function ()
{
return $('.sax-panel-item-template .sax-dropdown-menu.UserReportFilter li.sax-dropdown-item', $pnl.filter).clone();
}
sr.getItemTemplate = function ()
{
return $('.sax-panel-item-template .sax-panel-item.UserReport', $pnl.results).clone();
}
sr.getItemDropdownTemplate = function ()
{
return $('.sax-panel-item-template .sax-dropdown-menu.UserReport li.sax-dropdown-item', $pnl.results).clone();
}
sr.getFilterMenuOption = function (lbl, fn, cls)
{
return sr.getMenuOption(sr.getFilterDropdownTemplate(), lbl, fn, cls);
}
sr.getItemMenuOption = function (lbl, fn, cls)
{
return sr.getMenuOption(sr.getItemDropdownTemplate(), lbl, fn, cls);
}
sr.getMenuOption = function ($opt, lbl, fn, cls)
{
return $opt.find('div.sax-label').text(lbl).end().on('click', fn).addClass(cls);
}
//--------------------------------------------------------------
sr.createItem = function ()
{
sr.clearItem();
$dlg.rpt.dialog('option', 'title', sax.dlg.title.createUserReport);
sr.openDialog();
}
sr.openDialog = function ()
{
sax.openDialog($dlg.rpt, 800, 600);
}
sr.clearItem = function ()
{
let frm = $frm.rpt;
$('input.UserReportId,input.UserReportExists,input[type="text"],textarea,select', frm).val('');
sax.populateSelectCodeDesc('#cbUserReportType', sr.data.reportTypes);
sax.populateSelectCodeDesc('#cbUserReportStatus', sr.data.statuses);
$('.UserReportStatus', frm).val(sr.data.defaultStatusCode);
sax.clearControlErrors();
sr.cleanUp();
}
//--------------------------------------------------------------
sr.updateItem = function (item, $item)
{
sr.clearItem();
sr.data.$item = $item;
$('.UserReportId', $frm.rptId).val(item.id);
sr.ajax.updateItem = sr.ajax.updateItem || { url: sax.url.base + 'UserReport/Ajax/GetItem', formId: 'frmUserReportId', callbackFn: sr.onUpdateItem };
sax.doAjaxRequest(sr.ajax.updateItem, 50);
}
sr.onUpdateItem = function (response)
{
//sax.debug('onUpdateItem', response);
let frm = $frm.rpt;
if (!response.success) return;
let item = response.report;
$('.UserReportId', frm).val(item.id);
$('.UserReportExists', frm).val(1);
$('select.UserReportType', frm).remove('option[value=""],option:not([value])').val(item.reportTypeCode);
$('input.UserReportTitle', frm).val(item.title);
$('textarea.UserReportReport', frm).val(item.report);
$('select.UserReportStatus', frm).val(item.statusCode);
sax.clearControlErrors();
$dlg.rpt.dialog('option', 'title', sax.dlg.title.updateUserReport);
sr.openDialog();
}
//--------------------------------------------------------------
sr.storeItem = function ()
{
sr.ajax.storeItem = sr.ajax.storeItem || { url: sax.url.base + 'UserReport/Ajax/StoreItem', formId: 'frmUserReport', callbackFn: sr.onStoreItem };
sax.doAjaxRequest(sr.ajax.storeItem, 50);
}
sr.onStoreItem = function (response)
{
//sax.debug('onStoreItem', response);
sax.refreshControlValues(response.controlValues);
if (!response.success) return;
$dlg.rpt.dialog('close');
var item = response.report;
if (!sr.data.$item)
{
sr.data.$item = sr.getItemTemplate();
$('.sax-panel-item-list', $pnl.results).prepend(sr.data.$item).show();
}
sr.populateItem(sr.data.$item, item);
sr.cleanUp();
}
sr.cleanUp= function ()
{
delete sr.data.$item;
}
//--------------------------------------------------------------
$(function ()
{
$pnl.rpts = $('.sax-panel.UserReports');
$pnl.filter = $('.sax-panel-filter', $pnl.rpts);
$frm.filter = $('#frmUserReportFilter', $pnl.filter);
$('.FilterUserReport', $frm.filter).on('input', function () { sr.refreshResults(250); });
$pnl.results = $('.sax-panel-results', $pnl.rpts);
$pnl.msgs = $('.sax-panel-messages', $pnl.results);
$frm.rptId = $('#frmUserReportId');
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sr.storeItem(); };
opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); sr.cleanUp(); };
$dlg.rpt = $('#dlgUserReport').dialog(opt);
$frm.rpt = $('#frmUserReport');
$frm.rpt.on('input', '.sax-input', function () { sax.clearControlError(this); }).on('change', '.sax-select', function () { sax.clearControlError(this); });
setTimeout(sr.refreshResults, 250);
});
}(window, window.document));
/* The End */
@@ -186,6 +186,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
}
}
// Clear any remaining User Account Ids.
foreach (UserReportResponseListData userReportData in responseData.Reports.FindAll(item => item.UserAccountId != null))
userReportData.UserAccountId = null;
+9 -3
View File
@@ -93,11 +93,17 @@
return index % 2 == 1 ? (cName || "other") : "";
});
}
sax.populateSelect = function ($sel, values, code, desc)
{
code = code || 'code';
desc = desc || 'desc';
$sel = $($sel).empty();
for (const value of values || [])
$sel.append($('<option>').prop('value', value[code]).text(value[desc]));
}
sax.populateSelectCodeDesc = function ($sel, values)
{
$sel = $($sel).empty();
for (const value of values)
$sel.append($('<option>').prop('value', value.code).text(value.desc));
sax.populateSelect($sel, values);
}
sax.checkTextAreaMaxLength = function (ctrl, len)
{
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Saxonite.Net.Standard.Base.App
//-------------------------------------------------------------------
public static class Version
{
private static String version { get; } = "1.2.10.4";
private static String version { get; } = "1.2.10.5";
// Retrieve version.
public static String GetFullVersion () { return version; }
public static String GetAppVersion ()
@@ -299,9 +299,9 @@ namespace Saxonite.Net.Standard.Base.App
// Support.
// User Report Types.
userReportTypeCodes.Add(Sax.UserReportType.Enhancement, "Enhancement", "Enhancement request");
userReportTypeCodes.Add(Sax.UserReportType.Information, "Information", "Information request");
userReportTypeCodes.Add(Sax.UserReportType.Bug, "Bug", "Bug report");
userReportTypeCodes.Add(Sax.UserReportType.Enhancement, "ENH", "Enhancement request");
userReportTypeCodes.Add(Sax.UserReportType.Information, "INF", "Information request");
userReportTypeCodes.Add(Sax.UserReportType.Bug, "BUG", "Bug report");
//---------------------------------------------------------------
}
@@ -206,7 +206,7 @@ namespace Saxonite.Net.Standard.Dbas.Mgr
private void PopulateTo(UserSession_Db dbUserSession, SaxUserSession userSession, DbUpdateInfo dbUpdateInfo)
{
dbUserSession._UserAccountId = SysId.ToInt(userSession.UserAccountId);
dbUserSession._ActivityIndexIds= SysIdList.Concat(userSession.ActivityIndexIds, SaxUserSession.ActivityIndexDelim);
dbUserSession._ActivityIndexIds= SysIdCollection.Concat(userSession.ActivityIndexIds, SaxUserSession.ActivityIndexDelim);
dbUserSession._UserSessionData = userSession.UserSessionData;
// Common.
dbUserSession._Flags = (short)userSession.Flags;