This commit is contained in:
2022-03-03 18:46:08 +00:00
parent 1ac4c7f51a
commit 122056a9da
59 changed files with 1259 additions and 474 deletions
@@ -60,44 +60,49 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Core Database connection.
ISacsDatabase db = SaxGlobals.App.GetCoreDatabase(SessionContext);
// Database table row counts.
Dictionary<String, int> tableRowCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
String query =
"SELECT QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) AS[TableName], SUM(sPTN.Rows) AS[RowCount] " +
"FROM sys.objects AS sOBJ " +
"INNER JOIN sys.partitions AS sPTN ON sOBJ.object_id = sPTN.object_id " +
"WHERE sOBJ.type = 'U' AND sOBJ.is_ms_shipped = 0x0 AND index_id< 2 /*Index Id: 0:Heap,1:Clustered*/ " +
"GROUP BY sOBJ.schema_id, sOBJ.name";
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query))
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsDisposable> disposableItems = new DisposableCollection<SacsDisposable>())
{
while (dbResultSet != null && dbResultSet.NextRecord())
// Core Database connection.
ISacsDatabase db = SaxGlobals.App.GetCoreDatabase(SessionContext);
// Database table row counts.
Dictionary<String, int> tableRowCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
String query =
"SELECT QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) As [TableName], SUM(sPTN.Rows) As [RowCount] " +
"FROM sys.objects AS sOBJ " +
"INNER JOIN sys.partitions AS sPTN ON sOBJ.object_id = sPTN.object_id " +
"WHERE sOBJ.type = 'U' AND sOBJ.is_ms_shipped = 0x0 AND index_id< 2 /*Index Id: 0:Heap,1:Clustered*/ " +
"GROUP BY sOBJ.schema_id, sOBJ.name";
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query))
{
tableRowCounts.Add(dbResultSet.GetRecordValues().GetValue("TableName").ToString(), (int)dbResultSet.GetRecordValues().GetValue("RowCount").AsLong());
while (dbResultSet != null && dbResultSet.NextRecord())
{
tableRowCounts.Add(dbResultSet.GetRecordValues().GetValue("TableName").ToString(), (int)dbResultSet.GetRecordValues().GetValue("RowCount").AsLong());
}
}
}
// Core database tables.
List<DbDfnTable> tableDfns = db.GetTableDfns();
foreach (DbDfnTable tableDfn in tableDfns.OrderBy(item => item.Name))
{
// Filter by table name.
if (!StringUtil.IsEmpty(model.DatabaseFilter.Table) && !tableDfn.Name.ContainsCI(model.DatabaseFilter.Table))
continue;
// Core database tables.
List<DbDfnTable> tableDfns = db.GetTableDfns();
foreach (DbDfnTable tableDfn in tableDfns.OrderBy(item => item.Name))
{
// Filter by table name.
if (!StringUtil.IsEmpty(model.DatabaseFilter.Search) && !tableDfn.Name.ContainsCI(model.DatabaseFilter.Search))
continue;
DatabaseTableData tableData = new DatabaseTableData();
tableData.SchemaName = tableDfn.Schema;
tableData.TableName = tableDfn.Name;
tableData.QualifiedName = tableDfn.QualifiedName;
tableData.ColumnCount = tableDfn.ColumnCount;
tableData.IndexCount = tableDfn.IndexCount;
DatabaseTableData tableData = new DatabaseTableData();
tableData.SchemaName = tableDfn.Schema;
tableData.TableName = tableDfn.Name;
tableData.QualifiedName = tableDfn.QualifiedName;
tableData.ColumnCount = tableDfn.ColumnCount;
tableData.IndexCount = tableDfn.IndexCount;
// Row count.
tableData.RowCount = tableRowCounts.GetValueOrDefault(tableDfn.QuotedQualifiedName, 0);
// Row count.
tableData.RowCount = tableRowCounts.GetValueOrDefault(tableDfn.QuotedQualifiedName, 0);
responseData.Tables.Add(tableData);
responseData.Tables.Add(tableData);
}
}
// Complete response.
@@ -127,9 +132,9 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
//-------------------------------------------------------------------
[HttpPost]
[Route("System/Ajax/ValidateDatabaseSchema")]
public IActionResult Ajax_ValidateDatabaseSchema(Model_Sport model)
public IActionResult Ajax_ValidateDatabaseSchema(Model_System model)
{
String fn = GetType().Name + ".Ajax_GetDatabaseTables";
String fn = GetType().Name + ".Ajax_ValidateDatabaseSchema";
String messageTitle = Localiser["system.caption.database"];
AjaxResponse_ValidateDatabaseSchema responseData = new AjaxResponse_ValidateDatabaseSchema(model);
@@ -137,42 +142,47 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Core Database connection.
ISacsDatabase db = SaxGlobals.App.GetCoreDatabase(SessionContext);
// Retrieve XML database schema definition.
var assembly = typeof(SaxSystem_Dbas).GetTypeInfo().Assembly;
String xmlSchema = SacsResourceHelper.GetManifestResourceAsText(assembly, "", "SaxDbDfn_Core.xml");
if (StringUtil.IsEmpty(xmlSchema))
return Json(responseData.SetMessage(messageTitle, "Failed to extract XML schema definition."));
// Extract schema from XML definition.
SaDbProcess_ConvertDbSchema.Config cfgSchemaConvert = new SaDbProcess_ConvertDbSchema.Config();
SaDbProcess_ConvertDbSchema procSchemaConvert = new SaDbProcess_ConvertDbSchema(cfgSchemaConvert);
List<DbDfnTable> tables = procSchemaConvert.ConvertXmlToTables(xmlSchema);
if (procSchemaConvert.HasProcessError())
return Json(responseData.SetMessage(messageTitle, "Failed to convert XML schema: " + procSchemaConvert.GetProcessError()));
SaDbProcess_CompareDatabaseSchemas.Config cfgSchemaCompare = new SaDbProcess_CompareDatabaseSchemas.Config(tables, db);
cfgSchemaCompare.HideIdenticalObjects = true;
cfgSchemaCompare.IgnorePosition = true;
SaDbProcess_CompareDatabaseSchemas procSchemaCompare = new SaDbProcess_CompareDatabaseSchemas(cfgSchemaCompare);
procSchemaCompare.ProcessNotifier = this;
procSchemaCompare.RunProcess();
List<SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem> schemaComparisonItems = procSchemaCompare.GetSchemaComparisonItems();
foreach (SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem schemaComparisonItem in schemaComparisonItems)
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsDisposable> disposableItems = new DisposableCollection<SacsDisposable>())
{
DbSchemaItemResponseData item = new DbSchemaItemResponseData()
// Core Database connection.
ISacsDatabase db = SaxGlobals.App.GetCoreDatabase(SessionContext);
// Retrieve XML database schema definition.
var assembly = typeof(SaxSystem_Dbas).GetTypeInfo().Assembly;
String xmlSchema = SacsResourceHelper.GetManifestResourceAsText(assembly, "", "SaxDbDfn_Core.xml");
if (StringUtil.IsEmpty(xmlSchema))
return Json(responseData.SetMessage(messageTitle, "Failed to extract XML schema definition."));
// Extract schema from XML definition.
SaDbProcess_ConvertDbSchema.Config cfgSchemaConvert = new SaDbProcess_ConvertDbSchema.Config();
SaDbProcess_ConvertDbSchema procSchemaConvert = new SaDbProcess_ConvertDbSchema(cfgSchemaConvert);
List<DbDfnTable> tables = procSchemaConvert.ConvertXmlToTables(xmlSchema);
if (procSchemaConvert.HasProcessError())
return Json(responseData.SetMessage(messageTitle, "Failed to convert XML schema: " + procSchemaConvert.GetProcessError()));
SaDbProcess_CompareDatabaseSchemas.Config cfgSchemaCompare = new SaDbProcess_CompareDatabaseSchemas.Config(tables, db);
cfgSchemaCompare.HideIdenticalObjects = true;
cfgSchemaCompare.IgnorePosition = true;
SaDbProcess_CompareDatabaseSchemas procSchemaCompare = new SaDbProcess_CompareDatabaseSchemas(cfgSchemaCompare);
procSchemaCompare.ProcessNotifier = this;
procSchemaCompare.RunProcess();
List<SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem> schemaComparisonItems = procSchemaCompare.GetSchemaComparisonItems();
foreach (SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem schemaComparisonItem in schemaComparisonItems)
{
Id = schemaComparisonItem.Id,
TableName = schemaComparisonItem.TableName,
ColumnName = schemaComparisonItem.ColumnName,
ColumnPosition = schemaComparisonItem.ColumnPosition,
IndexName = schemaComparisonItem.IndexName,
Comment = schemaComparisonItem.Comment
};
responseData.Items.Add(item);
DbSchemaItemResponseData item = new DbSchemaItemResponseData()
{
Id = schemaComparisonItem.Id,
TableName = schemaComparisonItem.TableName,
ColumnName = schemaComparisonItem.ColumnName,
ColumnPosition = schemaComparisonItem.ColumnPosition,
IndexName = schemaComparisonItem.IndexName,
Comment = schemaComparisonItem.Comment
};
responseData.Items.Add(item);
}
}
// Complete response.
@@ -193,6 +203,194 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
{
}
//-------------------------------------------------------------------
// Database Table ajax request.
//-------------------------------------------------------------------
private class AjaxResponseData_Table
{
public AjaxResponseData_Table(DbDfnTable tableDfn)
{
Schema = tableDfn.Schema;
Name = tableDfn.Name;
if (!StringUtil.IsEmpty(tableDfn.Remarks))
Remarks = tableDfn.Remarks;
foreach (DbDfnColumn columnDfn in tableDfn.Columns)
Columns.Add(new AjaxResponseData_Column(columnDfn));
foreach (DbDfnIndex indexDfn in tableDfn.Indices)
Indices.Add(new AjaxResponseData_Index(indexDfn));
}
public String Schema { get; }
public String Name { get; }
public String QualifiedName { get { return (!StringUtil.IsEmpty(Schema) ? Schema + "." : "") + Name; } }
public String QuotedQualifiedName { get { return (!StringUtil.IsEmpty(Schema) ? "[" + Schema + "]." : "") + "[" + Name + "]"; } }
public String Remarks { get; set; } = String.Empty;
public List<AjaxResponse_Data.ItemLabelValue> Properties { get; } = new List<AjaxResponse_Data.ItemLabelValue>();
public List<AjaxResponseData_Column> Columns { get; } = new List<AjaxResponseData_Column>();
public List<AjaxResponseData_Index> Indices { get; } = new List<AjaxResponseData_Index>();
}
private class AjaxResponseData_Column
{
public int Pos { get; }
public String Name { get; }
public String Format { get; }
public String DataTypeName { get; }
public short? DataTypeNative { get; }
public String DataTypeNameNative { get; }
public bool? IsIdentity { get; }
public long? Size { get; }
public long? BufferLen { get; }
public short? DecimalDigits { get; }
public bool? Nullable { get; }
public bool? IsNullable { get; }
public String Remarks { get; }
public AjaxResponseData_Column(DbDfnColumn columnDfn)
{
Pos = columnDfn.Pos;
Name = columnDfn.Name;
Format = columnDfn.GetFormat();
if (!StringUtil.IsEmpty(columnDfn.DataTypeName))
DataTypeName = columnDfn.DataTypeName;
if (columnDfn.DataTypeNative > 0)
DataTypeNative = columnDfn.DataTypeNative;
if (!StringUtil.IsEmpty(columnDfn.DataTypeNameNative))
DataTypeNameNative = columnDfn.DataTypeNameNative;
if (columnDfn.IsIdentity)
IsIdentity = columnDfn.IsIdentity;
if (columnDfn.Size > 0)
Size = columnDfn.Size;
if (columnDfn.BufferLen > 0)
BufferLen = columnDfn.BufferLen;
if (columnDfn.DecimalDigits > 0)
DecimalDigits = columnDfn.DecimalDigits;
if (columnDfn.Nullable == DbColumnNullable.Nullable)
Nullable = true;
if (columnDfn.IsNullable)
IsNullable = columnDfn.IsNullable;
if (!StringUtil.IsEmpty(columnDfn.Remarks))
Remarks = columnDfn.Remarks;
}
}
private class AjaxResponseData_Index
{
public String Name { get; }
public int? IndexType { get; }
public bool? Unique { get; }
public bool? Primary { get; }
public bool? Clustered { get; }
public bool? Nullable { get; }
public int? Pages { get; }
public int? UniqueValues { get; }
public List<AjaxResponseData_IndexColumn> Columns { get; } = new List<AjaxResponseData_IndexColumn>();
public AjaxResponseData_Index(DbDfnIndex indexDfn)
{
Name = indexDfn.Name;
if (indexDfn.IndexType > 0)
IndexType = indexDfn.IndexType;
if (indexDfn.Unique)
Unique = indexDfn.Unique;
if (indexDfn.Primary)
Primary = indexDfn.Primary;
if (indexDfn.Clustered)
Clustered = indexDfn.Clustered;
if (indexDfn.Nullable)
Nullable = indexDfn.Nullable;
if (indexDfn.Pages > 0)
Pages = indexDfn.Pages;
if (indexDfn.UniqueValues > 0)
UniqueValues = indexDfn.UniqueValues;
foreach (DbDfnIndexColumn indexColumnDfn in indexDfn.Columns)
Columns.Add(new AjaxResponseData_IndexColumn(indexColumnDfn));
}
}
private class AjaxResponseData_IndexColumn
{
public short Seq { get; }
public String Name { get; }
public bool? Desc { get; }
public AjaxResponseData_IndexColumn(DbDfnIndexColumn indexColumnDfn)
{
Seq = indexColumnDfn.Seq;
Name = indexColumnDfn.Name;
if (!indexColumnDfn.Ascend)
Desc = true;
}
}
private class AjaxResponse_DatabaseTable : AjaxResponse_Data
{
// Construction.
public AjaxResponse_DatabaseTable(SaxModel_Admin model) : base(model) { }
// Database table.
public String PopupTitle { get; set; }
public AjaxResponseData_Table Table { get; set; }
}
//-------------------------------------------------------------------
[HttpPost]
[Route("System/Ajax/GetDatabaseTable")]
public IActionResult Ajax_GetDatabaseTable(Model_System model)
{
String fn = GetType().Name + ".Ajax_GetDatabaseTable";
String messageTitle = Localiser["system.caption.database"];
AjaxResponse_DatabaseTable responseData = new AjaxResponse_DatabaseTable(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<SacsDisposable> disposableItems = new DisposableCollection<SacsDisposable>())
{
// Parameters.
if (StringUtil.IsEmpty(model.DatabaseTable.Name))
return Json(responseData.SetMessage(messageTitle, "Table name must be supplied."));
// Core Database connection.
ISacsDatabase db = SaxGlobals.App.GetCoreDatabase(SessionContext);
// Table definition.
DbDfnTable tableDfn = db.GetTableDfn(model.DatabaseTable.Name, true);
if (tableDfn == null)
return Json(responseData.SetMessage(messageTitle, "Invalid Table name supplied."));
// Populate table response.
responseData.Table = new AjaxResponseData_Table(tableDfn);
responseData.PopupTitle = Localiser["label.table"] + ": " + tableDfn.Name;
// Database sizing.
String query = "Exec sp_SpaceUsed [" + tableDfn.QualifiedName + "];";
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query))
{
if (dbResultSet != null && dbResultSet.NextRecord())
{
// Row count.
long rows = StringUtil.ToLong(dbResultSet.GetRecordValues().GetValue("rows").ToString());
if (rows > 0)
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Rows", Value = rows.ToString() });
// Reserved space.
String reserved = dbResultSet.GetRecordValues().GetValue("reserved").AsString();
if (!StringUtil.IsEmpty(reserved))
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Reserved", Value = reserved });
// Data space.
String data = dbResultSet.GetRecordValues().GetValue("data").AsString();
if (!StringUtil.IsEmpty(data))
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Data", Value = data });
// Index space.
String index = dbResultSet.GetRecordValues().GetValue("index_size").AsString();
if (!StringUtil.IsEmpty(index))
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Indices", Value = index });
// Unused space.
String unused = dbResultSet.GetRecordValues().GetValue("unused").AsString();
if (!StringUtil.IsEmpty(unused))
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Unused", Value = unused });
}
}
}
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
}
//=======================================================================
@@ -38,7 +38,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
//-------------------------------------------------------------------
[HttpPost]
[Route("System/Ajax/GetLogFileList")]
public IActionResult Ajax_GetLogFileList(Model_Sport model)
public IActionResult Ajax_GetLogFileList(Model_System model)
{
String fn = GetType().Name + ".Ajax_GetLogFileList";
String messageTitle = Localiser["system.caption.logs"];
@@ -37,6 +37,7 @@ namespace Saxonite.Net.Core.Web.Admin.Models
//-------------------------------------------------------------------
// Sport properties.
public String SportId { get; set; }
public String SportIdParent { get; set; }
public String SportName { get; set; }
public String SportSpecialityLabelCode { get; set; }
public Sax.SportSpecialityLabel SportSpecialityLabel { get { return (Sax.SportSpecialityLabel)SportSpecialityLabelCodes.GetTypeForCode(SportSpecialityLabelCode); } }
@@ -49,47 +50,64 @@ namespace Saxonite.Net.Core.Web.Admin.Models
// Sport.
public bool ValidateSportData(SaxController_Base.AjaxResponse_Data responseData)
{
// Sport name.
if (SportName != null)
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
responseData.SetControlValue(nameof(SportName), SportName);
if (StringUtil.IsEmpty(SportName))
responseData.SetControlError(nameof(SportName), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(SportName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name))
responseData.SetControlError(nameof(SportName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name)]);
else
// Parent sport.
SysId sportIdParent = SportIdParent.ToSysId();
if (SportIdParent != null && SysId.IsValid(sportIdParent))
{
// Check for duplicate name.
SaxSport.Params prmSport = new SaxSport.Params();
SysId sportId = SportId.ToSysId();
if (SysId.IsValid(sportId))
prmSport.IdsExcluded.Add(sportId);
prmSport.NamePartial = SportName;
prmSport.StatusCat = SaxSport.StatusCat.Any;
if (ReferenceMgr.GetSportCount(prmSport) > 0)
responseData.SetControlError(nameof(SportName), Localiser["msg.validation.duplicate.value"]);
SaxSport sport = ReferenceMgr.GetSportById(SportIdParent.ToSysId());
disposableItems.Add(sport);
if (sport == null)
responseData.SetControlError(nameof(SportIdParent), Localiser["msg.validation.invalid.value"]);
else if (SysId.IsValid(sport.SportIdParent))
responseData.SetControlError(nameof(SportIdParent), Localiser["msg.validation.invalid.value"]);
}
}
// Sport Speciality Label.
if (SportSpecialityLabelCode != null)
{
if (!StringUtil.IsEmpty(SportSpecialityLabelCode))
// Sport name.
if (SportName != null)
{
if (SportSpecialityLabel <= 0)
responseData.SetControlError(nameof(SportSpecialityLabel), Localiser["msg.validation.invalid.value"]);
responseData.SetControlValue(nameof(SportName), SportName);
if (StringUtil.IsEmpty(SportName))
responseData.SetControlError(nameof(SportName), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(SportName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name))
responseData.SetControlError(nameof(SportName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name)]);
else
{
// Check for duplicate name.
SaxSport.Params prmSport = new SaxSport.Params();
SysId sportId = SportId.ToSysId();
if (SysId.IsValid(sportId))
prmSport.IdsExcluded.Add(sportId);
prmSport.NamePartial = SportName;
prmSport.StatusCat = SaxSport.StatusCat.Any;
if (ReferenceMgr.GetSportCount(prmSport) > 0)
responseData.SetControlError(nameof(SportName), Localiser["msg.validation.duplicate.value"]);
}
}
}
// Sport status.
if (SportStatusCode != null)
{
if (StringUtil.IsEmpty(SportStatusCode))
responseData.SetControlError(nameof(SportStatus), Localiser["msg.validation.mandatory.value"]);
else if (!SaxSport.ValidStatuses.Contains(SportStatus))
responseData.SetControlError(nameof(SportStatus), Localiser["msg.validation.invalid.value"]);
}
// Sport Speciality Label.
if (SportSpecialityLabelCode != null)
{
if (!StringUtil.IsEmpty(SportSpecialityLabelCode))
{
if (SportSpecialityLabel <= 0)
responseData.SetControlError(nameof(SportSpecialityLabel), Localiser["msg.validation.invalid.value"]);
}
}
// Sport status.
if (SportStatusCode != null)
{
if (StringUtil.IsEmpty(SportStatusCode))
responseData.SetControlError(nameof(SportStatus), Localiser["msg.validation.mandatory.value"]);
else if (!SaxSport.ValidStatuses.Contains(SportStatus))
responseData.SetControlError(nameof(SportStatus), Localiser["msg.validation.invalid.value"]);
}
}
return !responseData.HasControlErrors();
}
@@ -24,9 +24,14 @@ namespace Saxonite.Net.Core.Web.Admin.Models
// Database page properties.
public class DatabaseFilterData
{
public String Table { get; set; }
public String Search { get; set; }
}
public DatabaseFilterData DatabaseFilter { get; } = new DatabaseFilterData();
public class DatabaseTableData
{
public String Name { get; set; }
}
public DatabaseTableData DatabaseTable { get; } = new DatabaseTableData();
//-------------------------------------------------------------------
// Logs page properties.
@@ -147,6 +147,12 @@
<data name="home.msg.no.items.awaiting.activation" xml:space="preserve">
<value>No items are awaiting activation</value>
</data>
<data name="info.char.available" xml:space="preserve">
<value>[1 char available]</value>
</data>
<data name="info.chars.available" xml:space="preserve">
<value>[{0} chars available]</value>
</data>
<data name="label.accounts" xml:space="preserve">
<value>Accounts</value>
</data>
@@ -174,12 +180,6 @@
<data name="label.category" xml:space="preserve">
<value>Category</value>
</data>
<data name="label.characters.count" xml:space="preserve">
<value>{0} characters</value>
</data>
<data name="label.characters.one" xml:space="preserve">
<value>1 character</value>
</data>
<data name="label.clear" xml:space="preserve">
<value>Clear</value>
</data>
@@ -54,7 +54,7 @@
}
@* Scripts *@
<script>
<script>
var sax = sax || { page: {}, mdl: {}, url: {}, links: {}, form: {}, data: {}, ajax: {}, msg: {}, lbl: {}, dlg: { title: {}, btn: {} }, $frm: {}, $dlg: {}, $pnl: {}, session: {}, kli: {} };
sax.url.base = '@Model.RedirectLocation.Base';
sax.url.home = '@Model.RedirectLocation.Home';
@@ -70,8 +70,8 @@
sax.dlg.btn.ok = '@Localiser["label.ok"]';
sax.dlg.btn.close = '@Localiser["label.close"]';
sax.dlg.btn.cancel = '@Localiser["label.cancel"]';
sax.lbl.availableCharacter = '@Localiser.GetJavascriptText("label.characters.one")';
sax.lbl.availableCharacters = '@Localiser.GetJavascriptText("label.characters.count", "{0}")';
sax.lbl.charAvailable = '@Localiser.GetJavascriptText("info.char.available")';
sax.lbl.charsAvailable = '@Localiser.GetJavascriptText("info.chars.available", "{0}")';
sax.lbl.noneSelected = '@Localiser.GetJavascriptText("label.selected.none")';
sax.lbl.numberSelected = '@Localiser.GetJavascriptText("label.selected.count", "{0}")';
sax.msg.signOutConfirm = '@Localiser.GetJavascriptText("security.msg.signout.confirm")';
@@ -84,7 +84,7 @@
sax.kli.active = @keepLoggedIn;
sax.kli.interval = @(Sax.Config.Admin.Session.Cookie.KeepLoggedInTimeoutMillis);
sax.debugMode = @debug;
</script>
</script>
</head>
<body>
@@ -4,7 +4,7 @@
ViewData["Title"] = "System - Database";
}
<div class="container-fluid">
<div class="container-fluid DatabaseTables">
<div class="sax-panel-filter">
<div class="sax-header row">
@@ -14,11 +14,11 @@
</div>
</div>
<div class="sax-content">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmDatabaseFilter", @class = "sax-form", @onSubmit = "return false;" }))
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmDbTableFilter", @class = "sax-form", @onSubmit = "return false;" }))
{
<div class="row">
<div class="col-sm-5 sax-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-sm-7">@Html.TextBoxFor(model => model.DatabaseFilter.Table, new { @id = "ifFilterDatabaseTable", @class = "FilterDatabaseTable", @maxlength = "32" })</div>
<div class="col-sm-7">@Html.TextBoxFor(model => model.DatabaseFilter.Search, new { @id = "ifFilterDatabaseTable", @class = "FilterDatabaseTable", @maxlength = "32" })</div>
</div>
}
</div>
@@ -51,3 +51,75 @@
</div>
</div>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmDbTableName", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.DatabaseTable.Name, new { @class = "DatabaseTableName" })
}
<style>
#dlgDbTable tr.sax-heading td
{
color:#808080;
border-bottom: 1px solid #808080;
}
</style>
<div id="dlgDbTable" class="sax-panel-item-template">
<div class="">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmDbTable", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.DatabaseTable.Name, new { @class = "DatabaseTableName" })
}
<table>
<tr>
<td class="right pt2 pr8">Properties:</td>
<td>
<table class="TableProperties">
</table>
</td>
</tr>
<tr>
<td class="right pt2 pr8">Columns:</td>
<td>
<table class="TableColumns">
<tr class="sax-heading">
<td class="right pl8 pr8">Pos</td>
<td class="pl8 pr8">Name</td>
<td class="center">Format</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="right pt2 pr8">Indices:</td>
<td>
<table class="TableIndices">
<tr class="sax-heading">
<td class="pl8 pr8">Name</td>
<td class="center pl8 pr8">Unique</td>
<td class="pl8 pr8">Columns</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<div class="sax-panel-item-template">
<table>
<tr class="TableProperty">
<td class="sax-label Label right pl8 pr8"></td>
<td class="Value pl8 pr8"></td>
</tr>
<tr class="TableColumn">
<td class="Pos right pl8 pr8"></td>
<td class="Name pl8 pr8"></td>
<td class="Format center pl8 pr8"></td>
</tr>
<tr class="TableIndex">
<td class="Name pl8 pr16"></td>
<td class="Unique center"></td>
<td class="Columns pl8 pr8"></td>
</tr>
</table>
</div>
</div>
+22 -12
View File
@@ -103,24 +103,34 @@
if (ctrl == null || ctrl.value == null) return;
if (ctrl.value.length > len) ctrl.value = ctrl.value.substring(0, len);
}
sax.setAvailableCharsLabel = function ($if, max, $lbl)
sax.setAvailableCharsInfo = function ($if, max, $info)
{
var avail = Math.max(0, max - $if.val().length);
$lbl.text(avail == 1 ? sax.lbl.availableCharacter : sax.lbl.availableCharacters.replace(/\{0\}/g, avail));
let info = '';
if (max > 0)
{
let avail = Math.max(0, max - $if.val().length);
info = (avail == 1 ? sax.lbl.charAvailable : sax.lbl.charsAvailable.replace(/\{0\}/g, avail));
}
($info || $('.sax-info', $if.closest('.sax-form-control'))).text(info);
}
sax.setCharsAvailableLabel = function ($if, max)
{
var avail = Math.max(0, max - $if.val().length);
$('.sax-select-chars-available', $if.closest('.sax-form-control')).text(avail == 1 ? sax.lbl.availableCharacter : sax.lbl.availableCharacters.replace(/\{0\}/g, avail));
}
sax.setItemsSelectedLabel = function ($sel)
sax.setItemsSelectedInfo = function ($sel, $info)
{
var sel = $(':selected', $sel).length;
$('.sax-select-items-selected', $sel.closest('.sax-form-control')).text(sel == 0 ? sax.lbl.noneSelected : sax.lbl.numberSelected.replace(/\{0\}/g, sel));
($info || $('.sax-info', $sel.closest('.sax-form-control'))).text(sel == 0 ? sax.lbl.noneSelected : sax.lbl.numberSelected.replace(/\{0\}/g, sel));
}
sax.initCalendars = function (sel)
sax.initCalendars = function (sel, opt)
{
return $(sel).datepicker();
return $(sel).datepicker(opt || {});
}
sax.allowClearCalendar = function (sel)
{
$(sel).datepicker().on('keyup', function (e)
{
if (e.keyCode == 8 || e.keyCode == 46)
{
$(this).datepicker('setDate', null);
}
});
}
sax.refreshPaging = function (response, context, refreshFn)
{
+103 -38
View File
@@ -5,94 +5,159 @@
(function (win, doc, undef)
{
"use strict";
let sd = sax.sysDb = { $pnl: {}, $frm: {}, $dlg: {} };
let $pnl = sd.$pnl; let $frm = sd.$frm; let $dlg = sd.$dlg;
sax.itemIdPrefix = 'Itm_';
//--------------------------------------------------------------
sax.refreshResults = function (delay)
sd.refreshResults = function (delay)
{
var $results = $('.sax-panel-results');
if (!sax.awaitingRefreshResponse)
{
var $items = $('.sax-panel-item-list', $results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', $results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
var $items = $('.sax-panel-item-list', $pnl.results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', $pnl.results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
}
sax.ajax.refreshResults = sax.ajax.refreshResults || { url: sax.url.base + 'System/Ajax/GetDatabaseTables', formId: 'frmDatabaseFilter', callbackFn: sax.doRefreshResults };
sax.ajax.refreshResults = sax.ajax.refreshResults || { url: sax.url.base + 'System/Ajax/GetDatabaseTables', formId: 'frmDbTableFilter', callbackFn: sd.doRefreshResults };
sax.doAjaxRequest(sax.ajax.refreshResults, delay || 50);
sax.awaitingRefreshResponse = true;
}
sax.doRefreshResults = function (response)
sd.doRefreshResults = function (response)
{
//sax.debug('doRefreshResults', response);
delete sax.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
var $results = $('.sax-panel-results');
var $msgs = $('.sax-panel-messages', $results).hide().empty();
var $items = $('.sax-panel-item-list', $results).hide().empty();
var $tmpl = $('.sax-panel-item-template .sax-panel-item.DatabaseTable', $results);
var $msgs = $('.sax-panel-messages', $pnl.results).hide().empty();
var $items = $('.sax-panel-item-list', $pnl.results).hide().empty();
if (!response.success) return;
// Items.
var items = response.tables;
if (!items.length)
return $msgs.append($('<div class="sax-message">' + sax.msg.dataNoneFound + '</div>')).fadeIn(500);
for (let itemIdx = 0; itemIdx < items.length; itemIdx++)
{
let item = items[itemIdx];
let $item = $tmpl.clone();
sax.populateItem($item, item);
$items.append($item);
}
$items.append(sd.populateItem(sd.getTableTemplate(), items[itemIdx]));
$items.fadeIn(50);
}
sax.populateItem = function ($item, item)
sd.populateItem = function ($item, item)
{
if (!item) return;
if (!item) return $item;
$item.prop('id', sax.itemIdPrefix + item.id);
$('.TableName', $item).text(item.qualifiedName);
$('.RowCount', $item).text(item.rowCount);
$('.ColumnCount', $item).text(item.columnCount);
$('.IndexCount', $item).text(item.indexCount);
$('.sax-caption .sax-action, .sax-actions .sax-action.sax-item-view', $item).off('click').on('click', function () { sax.viewItem(item.id) })
$item.off('dblclick').on('dblclick', function () { sax.updateItem(item.id) })
$('.sax-caption .sax-action, .sax-actions .sax-action.sax-item-view', $item).off('click').on('click', function () { sd.viewItem(item) })
$item.off('dblclick').on('dblclick', function () { sax.viewItem(item) })
$('.sax-panel-results .sax-panel-messages').hide().empty();
return $item;
}
sd.getTableTemplate = function ()
{
return $('.sax-panel-item-template .sax-panel-item.DatabaseTable', $pnl.results).clone();
}
//--------------------------------------------------------------
sax.viewItem = function (id)
sd.viewItem = function (item)
{
$('.DatabaseTableName', sax.$frm.dbTableName).val(id);
sax.ajax.updateItem = sax.ajax.updateItem || { url: sax.url.base + 'System/Ajax/GetDatabaseTable', formId: 'frmDatabaseTableName', callbackFn: sax.onViewItem };
//sax.debug('viewItem', item.tableName, $frm.tableName, $('.DatabaseTableName', $frm.tableName))
$('.DatabaseTableName', $frm.tableName).val(item.tableName);
sax.ajax.updateItem = sax.ajax.updateItem || { url: sax.url.base + 'System/Ajax/GetDatabaseTable', formId: 'frmDbTableName', callbackFn: sd.onViewItem };
sax.doAjaxRequest(sax.ajax.updateItem, 50);
}
sax.onViewItem = function (response)
sd.onViewItem = function (response)
{
//sax.debug('onViewItem', response);
let $frm = sax.$frm.dbTable;
$('input[type="text"],textarea,select', $frm).val('');
sd.clearItem();
if (!response.success) return;
let item = response.table;
$('.DatabaseTableName', $frm).val(item.name);
let $frmT = $frm.table;
$('.DatabaseTableName', $frmT).val(item.name);
// Properties.
let prts = item.properties;
let $prts = $('.TableProperties', $dlg.table);
$('tr:not(.sax-heading)', $prts).remove();
for (let prtIdx = 0; prtIdx < prts.length; prtIdx++)
{
let prt = prts[prtIdx];
let $prt = sd.getTablePropertyTemplate();
$('.Label', $prt).text(prt.label);
$('.Value', $prt).text(prt.value);
$prts.append($prt);
}
// Columns.
let cols = item.columns;
let $cols = $('.TableColumns', $dlg.table);
$('tr:not(.sax-heading)', $cols).remove();
for (let colIdx = 0; colIdx < cols.length; colIdx++)
{
let col = cols[colIdx];
let $col = sd.getTableColumnTemplate();
$('.Pos', $col).text(col.pos);
$('.Name', $col).text(col.name);
$('.Format', $col).text(col.format);
$cols.append($col);
}
// Indices.
let idxs = item.indices;
let $idxs = $('.TableIndices', $dlg.table);
$('tr:not(.sax-heading)', $idxs).remove();
for (let idxIdx = 0; idxIdx < idxs.length; idxIdx++)
{
let idx = idxs[idxIdx];
let $idx = sd.getTableIndexTemplate();
$('.Name', $idx).text(idx.name);
for (const col of idx.columns)
$('.Columns', $idx).append($('<div>').text(col.name));
$('.Unique', $idx).text(idx.unique?'Yes':'');
$idxs.append($idx);
}
// Display table details.
$dlg.table.dialog('option', 'title', response.popupTitle || "Table: " + item.name);
sax.openDialog($dlg.table, 600, 600);
}
sd.clearItem = function ()
{
let $frmT = $frm.table;
$('input[type="text"],textarea,select', $frmT).val('');
sax.clearControlErrors();
sax.$dlg.dbTable.dialog('option', 'title', sax.dlg.title.viewDatabaseTable);
sax.openDialog(sax.$dlg.dbTable, 600, 600);
}
sd.getTablePropertyTemplate = function ()
{
return sd.getTableRowTemplate('TableProperty');
}
sd.getTableColumnTemplate = function ()
{
return sd.getTableRowTemplate('TableColumn');
}
sd.getTableIndexTemplate = function ()
{
return sd.getTableRowTemplate('TableIndex');
}
sd.getTableRowTemplate = function (name)
{
return $('.sax-panel-item-template .'+name, $dlg.table).clone();
}
//--------------------------------------------------------------
$(function ()
{
$('.sax-action.sax-results-refresh').on('click', function () { sax.refreshResults(); });
$pnl.tables = $('.DatabaseTables');
$pnl.filter = $('.sax-panel-filter', $pnl.tables);
$pnl.results = $('.sax-panel-results', $pnl.tables);
$pnl.filter.on('click', '.sax-action.sax-results-refresh', function () { sd.refreshResults(); });
$('.sax-input').on('input', function () { sax.clearControlError(this); });
sax.$frm.filter = $('#frmDatabaseFilter');
$('.FilterDatabaseTable', sax.$frm.filter).on('input', function () { sax.refreshResults(250); });
sax.$frm.dbTableName = $('#frmDatabaseTableName');
sax.$frm.dbTable = $('#frmDatabaseTable');
$frm.filter = $('#frmDbTableFilter');
$('.FilterDatabaseTable', $frm.filter).on('input', function () { sd.refreshResults(250); });
$frm.tableName = $('#frmDbTableName');
$frm.table = $('#frmDbTable');
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sax.storeItem(); };
opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); };
sax.$dlg.dbTable = $('#dlgDatabaseTable').dialog(opt);
//opt.buttons[sax.dlg.btn.ok] = function () { sax.storeItem(); };
opt.buttons[sax.dlg.btn.close] = function () { $(this).dialog('close'); };
$dlg.table = $('#dlgDbTable').dialog(opt);
setTimeout(sax.refreshResults, 250);
setTimeout(sd.refreshResults, 250);
});
}(window, window.document));
@@ -264,7 +264,7 @@
//--------------------------------------------------------------
sax.userEmails = function (item)
{
sax.debug('userEmails', item);
//sax.debug('userEmails', item);
let frm = $frm.emailsl
$('.UserId', frm).val(item.id);
$('.UserEmailAddress', frm).val(item.emailAddress);