refactor: remove unused classes and consolidate ViewModels in Core

Remove 9 unused types from Core (duplicate extension classes, TableSpec, ColumnSpec, LotLocation), move ComponentLotViewModel and OperatorViewModel from Client to Core, and refactor DataSync.Dev to use pipeline-based configuration. Fix Login.razor to use UserInfoDto directly.
This commit is contained in:
Joseph Doherty
2026-01-19 00:13:12 -05:00
parent 80057590f4
commit 7e36bb4225
89 changed files with 1049 additions and 2282 deletions
@@ -0,0 +1,54 @@
using JdeScoping.Core.Models;
namespace JdeScoping.Core.ApiContracts.Auth;
/// <summary>
/// API response DTO for authenticated user information.
/// </summary>
public record UserInfoDto
{
/// <summary>
/// User's login username.
/// </summary>
public string Username { get; init; } = string.Empty;
/// <summary>
/// User's first name.
/// </summary>
public string FirstName { get; init; } = string.Empty;
/// <summary>
/// User's last name.
/// </summary>
public string LastName { get; init; } = string.Empty;
/// <summary>
/// User's display name (computed on server).
/// </summary>
public string DisplayName { get; init; } = string.Empty;
/// <summary>
/// User's organization title.
/// </summary>
public string Title { get; init; } = string.Empty;
/// <summary>
/// User's email address.
/// </summary>
public string EmailAddress { get; init; } = string.Empty;
/// <summary>
/// Creates a UserInfoDto from a UserInfo entity.
/// </summary>
/// <param name="userInfo">The UserInfo entity to convert.</param>
/// <returns>A new UserInfoDto instance.</returns>
public static UserInfoDto FromUserInfo(UserInfo userInfo) => new()
{
Username = userInfo.Username,
FirstName = userInfo.FirstName,
LastName = userInfo.LastName,
DisplayName = userInfo.DisplayName,
Title = userInfo.Title,
EmailAddress = userInfo.EmailAddress
};
}
@@ -1,5 +1,5 @@
using JdeScoping.Core.ApiContracts.Auth;
using JdeScoping.Core.ApiContracts.Results;
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.Auth;
namespace JdeScoping.Core.ApiContracts;
@@ -19,5 +19,5 @@ public interface IAuthApiClient
Task<ApiResult<Unit>> LogoutAsync(CancellationToken ct = default);
/// <summary>Gets the current authenticated user's information.</summary>
Task<ApiResult<UserInfo>> GetCurrentUserAsync(CancellationToken ct = default);
Task<ApiResult<UserInfoDto>> GetCurrentUserAsync(CancellationToken ct = default);
}
@@ -44,4 +44,8 @@ public record PipelineScheduleDto(
bool ReIndex,
bool IntervalIsOverride,
bool PrePurgeIsOverride,
bool ReIndexIsOverride);
bool ReIndexIsOverride,
string? Query,
List<PipelineParameterDto> Parameters,
List<string>? PreScripts,
List<string>? PostScripts);
@@ -1,6 +1,6 @@
namespace JdeScoping.Core.ApiContracts.Pipelines;
using JdeScoping.Core.Models.Enums;
using Models.Enums;
/// <summary>
/// Pipeline execution history.
@@ -1,6 +1,6 @@
namespace JdeScoping.Core.ApiContracts.Pipelines;
using JdeScoping.Core.Models.Enums;
using Models.Enums;
/// <summary>
/// Pipeline schedule status for each update type.
@@ -0,0 +1,60 @@
using JdeScoping.Core.Models.Search;
namespace JdeScoping.Core.ApiContracts.SignalR;
/// <summary>
/// SignalR message DTO for search status updates.
/// </summary>
public record SearchUpdateDto
{
/// <summary>
/// Search PK ID.
/// </summary>
public int Id { get; init; }
/// <summary>
/// User-friendly name for the search.
/// </summary>
public string Name { get; init; } = string.Empty;
/// <summary>
/// User name of user that submitted the search.
/// </summary>
public string UserName { get; init; } = string.Empty;
/// <summary>
/// Current search status (serialized as string).
/// </summary>
public string Status { get; init; } = string.Empty;
/// <summary>
/// Timestamp search was submitted.
/// </summary>
public DateTime? SubmitDt { get; init; }
/// <summary>
/// Timestamp search was started.
/// </summary>
public DateTime? StartDt { get; init; }
/// <summary>
/// Timestamp search was completed.
/// </summary>
public DateTime? EndDt { get; init; }
/// <summary>
/// Creates a SearchUpdateDto from a Search entity.
/// </summary>
/// <param name="search">The Search entity to convert.</param>
/// <returns>A new SearchUpdateDto instance.</returns>
public static SearchUpdateDto FromSearch(Search search) => new()
{
Id = search.Id,
Name = search.Name,
UserName = search.UserName,
Status = search.Status.ToString(),
SubmitDt = search.SubmitDt,
StartDt = search.StartDt,
EndDt = search.EndDt
};
}
@@ -0,0 +1,28 @@
namespace JdeScoping.Core.ApiContracts.SignalR;
/// <summary>
/// SignalR message DTO for processor status updates.
/// </summary>
public record StatusUpdateDto
{
/// <summary>
/// Status message to display.
/// </summary>
public string Message { get; init; } = string.Empty;
/// <summary>
/// Timestamp when message was generated.
/// </summary>
public DateTime? Timestamp { get; init; }
/// <summary>
/// Creates a StatusUpdateDto with the current timestamp.
/// </summary>
/// <param name="message">Status message.</param>
/// <returns>A new StatusUpdateDto instance.</returns>
public static StatusUpdateDto Create(string message) => new()
{
Message = message,
Timestamp = DateTime.UtcNow
};
}
@@ -1,35 +0,0 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.Inventory;
using JdeScoping.Core.ViewModels;
namespace JdeScoping.Core.Extensions;
/// <summary>
/// Extension methods for Item entity
/// </summary>
public static class ItemExtensions
{
/// <summary>
/// Converts an Item entity to its ViewModel projection
/// </summary>
/// <param name="item">Item entity to convert</param>
/// <returns>ItemViewModel projection</returns>
public static ItemViewModel ToViewModel(this Item item)
{
return new ItemViewModel
{
ItemNumber = item.ItemNumber,
Description = item.Description
};
}
/// <summary>
/// Converts a collection of Item entities to ViewModels
/// </summary>
/// <param name="items">Collection of Item entities</param>
/// <returns>Collection of ItemViewModel projections</returns>
public static IEnumerable<ItemViewModel> ToViewModels(this IEnumerable<Item> items)
{
return items.Select(i => i.ToViewModel());
}
}
@@ -1,36 +0,0 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.Organization;
using JdeScoping.Core.ViewModels;
namespace JdeScoping.Core.Extensions;
/// <summary>
/// Extension methods for JdeUser entity
/// </summary>
public static class JdeUserExtensions
{
/// <summary>
/// Converts a JdeUser entity to its ViewModel projection
/// </summary>
/// <param name="jdeUser">JdeUser entity to convert</param>
/// <returns>JdeUserViewModel projection</returns>
public static JdeUserViewModel ToViewModel(this JdeUser jdeUser)
{
return new JdeUserViewModel
{
AddressNumber = jdeUser.AddressNumber,
UserId = jdeUser.UserId,
FullName = jdeUser.FullName
};
}
/// <summary>
/// Converts a collection of JdeUser entities to ViewModels
/// </summary>
/// <param name="jdeUsers">Collection of JdeUser entities</param>
/// <returns>Collection of JdeUserViewModel projections</returns>
public static IEnumerable<JdeUserViewModel> ToViewModels(this IEnumerable<JdeUser> jdeUsers)
{
return jdeUsers.Select(u => u.ToViewModel());
}
}
@@ -1,35 +0,0 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.Inventory;
using JdeScoping.Core.ViewModels;
namespace JdeScoping.Core.Extensions;
/// <summary>
/// Extension methods for Lot entity
/// </summary>
public static class LotExtensions
{
/// <summary>
/// Converts a Lot entity to its ViewModel projection
/// </summary>
/// <param name="lot">Lot entity to convert</param>
/// <returns>LotViewModel projection</returns>
public static LotViewModel ToViewModel(this Lot lot)
{
return new LotViewModel
{
LotNumber = lot.LotNumber,
ItemNumber = lot.ItemNumber
};
}
/// <summary>
/// Converts a collection of Lot entities to ViewModels
/// </summary>
/// <param name="lots">Collection of Lot entities</param>
/// <returns>Collection of LotViewModel projections</returns>
public static IEnumerable<LotViewModel> ToViewModels(this IEnumerable<Lot> lots)
{
return lots.Select(l => l.ToViewModel());
}
}
@@ -1,35 +0,0 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.Organization;
using JdeScoping.Core.ViewModels;
namespace JdeScoping.Core.Extensions;
/// <summary>
/// Extension methods for ProfitCenter entity
/// </summary>
public static class ProfitCenterExtensions
{
/// <summary>
/// Converts a ProfitCenter entity to its ViewModel projection
/// </summary>
/// <param name="profitCenter">ProfitCenter entity to convert</param>
/// <returns>ProfitCenterViewModel projection</returns>
public static ProfitCenterViewModel ToViewModel(this ProfitCenter profitCenter)
{
return new ProfitCenterViewModel
{
Code = profitCenter.Code,
Description = profitCenter.Description
};
}
/// <summary>
/// Converts a collection of ProfitCenter entities to ViewModels
/// </summary>
/// <param name="profitCenters">Collection of ProfitCenter entities</param>
/// <returns>Collection of ProfitCenterViewModel projections</returns>
public static IEnumerable<ProfitCenterViewModel> ToViewModels(this IEnumerable<ProfitCenter> profitCenters)
{
return profitCenters.Select(pc => pc.ToViewModel());
}
}
@@ -1,35 +0,0 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.Organization;
using JdeScoping.Core.ViewModels;
namespace JdeScoping.Core.Extensions;
/// <summary>
/// Extension methods for WorkCenter entity
/// </summary>
public static class WorkCenterExtensions
{
/// <summary>
/// Converts a WorkCenter entity to its ViewModel projection
/// </summary>
/// <param name="workCenter">WorkCenter entity to convert</param>
/// <returns>WorkCenterViewModel projection</returns>
public static WorkCenterViewModel ToViewModel(this WorkCenter workCenter)
{
return new WorkCenterViewModel
{
Code = workCenter.Code,
Description = workCenter.Description
};
}
/// <summary>
/// Converts a collection of WorkCenter entities to ViewModels
/// </summary>
/// <param name="workCenters">Collection of WorkCenter entities</param>
/// <returns>Collection of WorkCenterViewModel projections</returns>
public static IEnumerable<WorkCenterViewModel> ToViewModels(this IEnumerable<WorkCenter> workCenters)
{
return workCenters.Select(wc => wc.ToViewModel());
}
}
@@ -1,35 +0,0 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.Models.WorkOrders;
using JdeScoping.Core.ViewModels;
namespace JdeScoping.Core.Extensions;
/// <summary>
/// Extension methods for WorkOrder entity
/// </summary>
public static class WorkOrderExtensions
{
/// <summary>
/// Converts a WorkOrder entity to its ViewModel projection
/// </summary>
/// <param name="workOrder">WorkOrder entity to convert</param>
/// <returns>WorkOrderViewModel projection</returns>
public static WorkOrderViewModel ToViewModel(this WorkOrder workOrder)
{
return new WorkOrderViewModel
{
WorkOrderNumber = workOrder.WorkOrderNumber,
ItemNumber = workOrder.ItemNumber
};
}
/// <summary>
/// Converts a collection of WorkOrder entities to ViewModels
/// </summary>
/// <param name="workOrders">Collection of WorkOrder entities</param>
/// <returns>Collection of WorkOrderViewModel projections</returns>
public static IEnumerable<WorkOrderViewModel> ToViewModels(this IEnumerable<WorkOrder> workOrders)
{
return workOrders.Select(wo => wo.ToViewModel());
}
}
@@ -1,4 +1,4 @@
using JdeScoping.Core.Models;
using JdeScoping.Core.ApiContracts.Auth;
namespace JdeScoping.Core.Models.Auth;
@@ -11,4 +11,4 @@ namespace JdeScoping.Core.Models.Auth;
public record LoginResultModel(
bool Success,
string? ErrorMessage,
UserInfo? User);
UserInfoDto? User);
@@ -1,35 +0,0 @@
namespace JdeScoping.Core.Models.Infrastructure;
/// <summary>
/// Database column specification
/// </summary>
public class ColumnSpec
{
/// <summary>
/// Column name
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Column definition (SQL type and constraints)
/// </summary>
public string Definition { get; set; } = string.Empty;
/// <summary>
/// Default constructor
/// </summary>
public ColumnSpec()
{
}
/// <summary>
/// Constructor with name and definition
/// </summary>
/// <param name="name">Column name</param>
/// <param name="definition">Column definition</param>
public ColumnSpec(string name, string definition)
{
Name = name;
Definition = definition;
}
}
@@ -1,83 +0,0 @@
namespace JdeScoping.Core.Models.Infrastructure;
/// <summary>
/// Database table specification for dynamic SQL generation
/// </summary>
public class TableSpec
{
/// <summary>
/// Table name
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Temporary table name (computed as # + Name)
/// </summary>
public string TempTableName => $"#{Name}";
/// <summary>
/// Table columns
/// </summary>
public List<ColumnSpec> Columns { get; set; } = [];
/// <summary>
/// Table columns that form the primary key
/// </summary>
public List<ColumnSpec> PrimaryKey { get; set; } = [];
/// <summary>
/// Default constructor
/// </summary>
public TableSpec()
{
}
/// <summary>
/// Constructor with table name
/// </summary>
/// <param name="name">Table name</param>
public TableSpec(string name)
{
Name = name;
}
/// <summary>
/// Generates SQL for creating an index on the primary key (stub)
/// </summary>
/// <returns>SQL CREATE INDEX statement</returns>
public string GenerateIndex()
{
// Stub implementation - to be expanded based on spec
return string.Empty;
}
/// <summary>
/// Generates SQL for dropping the table (stub)
/// </summary>
/// <returns>SQL DROP TABLE statement</returns>
public string GenerateDrop()
{
// Stub implementation - to be expanded based on spec
return string.Empty;
}
/// <summary>
/// Generates SQL for creating the table (stub)
/// </summary>
/// <returns>SQL CREATE TABLE statement</returns>
public string GenerateCreate()
{
// Stub implementation - to be expanded based on spec
return string.Empty;
}
/// <summary>
/// Gets a column specification by name (stub)
/// </summary>
/// <param name="columnName">Name of column to find</param>
/// <returns>ColumnSpec or null if not found</returns>
public ColumnSpec? GetColumn(string columnName)
{
return Columns.Find(c => c.Name == columnName);
}
}
@@ -1,32 +0,0 @@
namespace JdeScoping.Core.Models.Inventory;
/// <summary>
/// JDE lot location entity
/// </summary>
public class LotLocation
{
/// <summary>
/// Lot unique number
/// </summary>
public string LotNumber { get; set; } = string.Empty;
/// <summary>
/// Short item number
/// </summary>
public long ShortItemNumber { get; set; }
/// <summary>
/// Business unit unique code
/// </summary>
public string BranchCode { get; set; } = string.Empty;
/// <summary>
/// Location code where lot is located
/// </summary>
public string Location { get; set; } = string.Empty;
/// <summary>
/// Timestamp of last update to record
/// </summary>
public DateTime? LastUpdateDt { get; set; }
}
@@ -0,0 +1,21 @@
namespace JdeScoping.Core.ViewModels;
/// <summary>
/// View model for component lot filter.
/// </summary>
public class ComponentLotViewModel
{
public string LotNumber { get; set; } = string.Empty;
public string ItemNumber { get; set; } = string.Empty;
public override bool Equals(object? obj)
{
if (obj is ComponentLotViewModel other)
{
return LotNumber == other.LotNumber && ItemNumber == other.ItemNumber;
}
return false;
}
public override int GetHashCode() => HashCode.Combine(LotNumber, ItemNumber);
}
@@ -0,0 +1,22 @@
namespace JdeScoping.Core.ViewModels;
/// <summary>
/// View model for operator filter.
/// </summary>
public class OperatorViewModel
{
public int AddressNumber { get; set; }
public string UserId { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
public override bool Equals(object? obj)
{
if (obj is OperatorViewModel other)
{
return UserId == other.UserId;
}
return false;
}
public override int GetHashCode() => UserId.GetHashCode();
}