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:
@@ -1,6 +1,6 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Security.Claims;
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.ApiContracts.Auth;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
|
||||
namespace JdeScoping.Client.Auth;
|
||||
@@ -46,14 +46,14 @@ public class AuthStateProvider : AuthenticationStateProvider
|
||||
/// Validates the current session by calling /api/auth/me.
|
||||
/// Returns null if not authenticated.
|
||||
/// </summary>
|
||||
private async Task<UserInfoViewModel?> ValidateSessionAsync()
|
||||
private async Task<UserInfoDto?> ValidateSessionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetAsync("api/auth/me");
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return await response.Content.ReadFromJsonAsync<UserInfoViewModel>();
|
||||
return await response.Content.ReadFromJsonAsync<UserInfoDto>();
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -67,7 +67,7 @@ public class AuthStateProvider : AuthenticationStateProvider
|
||||
/// <summary>
|
||||
/// Creates an authenticated state from user info.
|
||||
/// </summary>
|
||||
private static AuthenticationState CreateAuthState(UserInfoViewModel user)
|
||||
private static AuthenticationState CreateAuthState(UserInfoDto user)
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
@@ -87,7 +87,7 @@ public class AuthStateProvider : AuthenticationStateProvider
|
||||
/// <summary>
|
||||
/// Called after successful login to update auth state.
|
||||
/// </summary>
|
||||
public async Task MarkUserAsAuthenticated(UserInfoViewModel user)
|
||||
public async Task MarkUserAsAuthenticated(UserInfoDto user)
|
||||
{
|
||||
await _userStorage.SetUserAsync(user);
|
||||
NotifyAuthenticationStateChanged(Task.FromResult(CreateAuthState(user)));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.ApiContracts.Auth;
|
||||
|
||||
namespace JdeScoping.Client.Auth;
|
||||
|
||||
@@ -12,12 +12,12 @@ public interface IUserStorageService
|
||||
/// <summary>
|
||||
/// Gets the stored user info.
|
||||
/// </summary>
|
||||
Task<UserInfoViewModel?> GetUserAsync();
|
||||
Task<UserInfoDto?> GetUserAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Stores the user info.
|
||||
/// </summary>
|
||||
Task SetUserAsync(UserInfoViewModel user);
|
||||
Task SetUserAsync(UserInfoDto user);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the stored user info.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.ApiContracts.Auth;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace JdeScoping.Client.Auth;
|
||||
@@ -19,7 +19,7 @@ public class UserStorageService : IUserStorageService
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public async Task<UserInfoViewModel?> GetUserAsync()
|
||||
public async Task<UserInfoDto?> GetUserAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -29,7 +29,7 @@ public class UserStorageService : IUserStorageService
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize<UserInfoViewModel>(json, new JsonSerializerOptions
|
||||
return JsonSerializer.Deserialize<UserInfoDto>(json, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
@@ -40,7 +40,7 @@ public class UserStorageService : IUserStorageService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SetUserAsync(UserInfoViewModel user)
|
||||
public async Task SetUserAsync(UserInfoDto user)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(user);
|
||||
await _jsRuntime.InvokeVoidAsync("jdeScopingInterop.setSessionStorage", UserKey, json);
|
||||
|
||||
@@ -51,16 +51,42 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(QueryPreview))
|
||||
@if (Config.Parameters?.Count > 0)
|
||||
{
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" class="rz-mb-2">Parameters</RadzenText>
|
||||
<ul class="rz-mb-4">
|
||||
@foreach (var param in Config.Parameters)
|
||||
{
|
||||
<li><strong>@param.Name</strong>: @(param.Format ?? "default") (source: @param.Source)</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(Config.Query))
|
||||
{
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" class="rz-mb-2">Query</RadzenText>
|
||||
<div style="background: #f5f5f5; padding: 0.75rem; border-radius: 4px; font-family: monospace; font-size: 0.875rem;">
|
||||
@QueryPreview
|
||||
</div>
|
||||
@if (!string.IsNullOrWhiteSpace(FullQuery))
|
||||
<pre style="background: #f8f9fa; padding: 1rem; border-radius: 4px; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: 0.875rem; line-height: 1.5; overflow-x: auto; white-space: pre-wrap; word-break: break-word; max-height: 400px; overflow-y: auto;">@FormatSql(Config.Query)</pre>
|
||||
}
|
||||
|
||||
@if (Config.PreScripts?.Count > 0)
|
||||
{
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" class="rz-mt-4 rz-mb-2">Pre-Scripts (@Config.PreScripts.Count)</RadzenText>
|
||||
@for (int i = 0; i < Config.PreScripts.Count; i++)
|
||||
{
|
||||
<RadzenButton Text="View Full Query" Icon="open_in_new" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
|
||||
Click="@(() => OnViewQuery.InvokeAsync(FullQuery))" class="rz-mt-2" />
|
||||
var script = Config.PreScripts[i];
|
||||
<RadzenText TextStyle="TextStyle.Body2" class="rz-mb-1"><strong>Script @(i + 1):</strong></RadzenText>
|
||||
<pre style="background: #fff3cd; padding: 0.75rem; border-radius: 4px; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: 0.8rem; line-height: 1.4; overflow-x: auto; white-space: pre-wrap; word-break: break-word; max-height: 200px; overflow-y: auto; margin-bottom: 0.5rem;">@FormatSql(script)</pre>
|
||||
}
|
||||
}
|
||||
|
||||
@if (Config.PostScripts?.Count > 0)
|
||||
{
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" class="rz-mt-4 rz-mb-2">Post-Scripts (@Config.PostScripts.Count)</RadzenText>
|
||||
@for (int i = 0; i < Config.PostScripts.Count; i++)
|
||||
{
|
||||
var script = Config.PostScripts[i];
|
||||
<RadzenText TextStyle="TextStyle.Body2" class="rz-mb-1"><strong>Script @(i + 1):</strong></RadzenText>
|
||||
<pre style="background: #d1ecf1; padding: 0.75rem; border-radius: 4px; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: 0.8rem; line-height: 1.4; overflow-x: auto; white-space: pre-wrap; word-break: break-word; max-height: 200px; overflow-y: auto; margin-bottom: 0.5rem;">@FormatSql(script)</pre>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,9 +95,6 @@
|
||||
@code {
|
||||
[Parameter] public UpdateTypes ScheduleType { get; set; }
|
||||
[Parameter] public PipelineScheduleDto? Config { get; set; }
|
||||
[Parameter] public string? QueryPreview { get; set; }
|
||||
[Parameter] public string? FullQuery { get; set; }
|
||||
[Parameter] public EventCallback<string> OnViewQuery { get; set; }
|
||||
|
||||
private static string GetScheduleTypeName(UpdateTypes type) => type switch
|
||||
{
|
||||
@@ -89,4 +112,50 @@
|
||||
return $"{minutes / 60} hour(s) ({minutes} min)";
|
||||
return $"{minutes} minutes";
|
||||
}
|
||||
|
||||
private static string FormatSql(string? sql)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
return "";
|
||||
|
||||
// Format SELECT columns - put each column on its own line
|
||||
var result = FormatSelectColumns(sql);
|
||||
|
||||
// Add line breaks before major clauses
|
||||
result = result
|
||||
.Replace(" FROM ", "\nFROM ")
|
||||
.Replace(" WHERE ", "\nWHERE ")
|
||||
.Replace(" AND ", "\n AND ")
|
||||
.Replace(" OR ", "\n OR ")
|
||||
.Replace(" LEFT ", "\nLEFT ")
|
||||
.Replace(" RIGHT ", "\nRIGHT ")
|
||||
.Replace(" INNER ", "\nINNER ")
|
||||
.Replace(" OUTER ", "\nOUTER ")
|
||||
.Replace(" JOIN ", " JOIN\n ")
|
||||
.Replace(" ORDER BY ", "\nORDER BY ")
|
||||
.Replace(" GROUP BY ", "\nGROUP BY ")
|
||||
.Replace(" HAVING ", "\nHAVING ");
|
||||
|
||||
return result.Trim();
|
||||
}
|
||||
|
||||
private static string FormatSelectColumns(string sql)
|
||||
{
|
||||
var selectIndex = sql.IndexOf("SELECT", StringComparison.OrdinalIgnoreCase);
|
||||
var fromIndex = sql.IndexOf(" FROM ", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (selectIndex < 0 || fromIndex < 0 || fromIndex <= selectIndex)
|
||||
return sql;
|
||||
|
||||
var beforeSelect = sql[..selectIndex];
|
||||
var selectKeyword = sql.Substring(selectIndex, 6);
|
||||
var columnsStart = selectIndex + 6;
|
||||
var columns = sql[columnsStart..fromIndex];
|
||||
var afterColumns = sql[fromIndex..];
|
||||
|
||||
var columnList = columns.Split(',');
|
||||
var formattedColumns = string.Join(",\n ", columnList.Select(c => c.Trim()));
|
||||
|
||||
return $"{beforeSelect}{selectKeyword} {formattedColumns}{afterColumns}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +90,11 @@
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
return "";
|
||||
|
||||
// Basic SQL formatting - add line breaks before major clauses
|
||||
return sql
|
||||
.Replace(" SELECT ", "\nSELECT ")
|
||||
// Format SELECT columns - put each column on its own line
|
||||
var result = FormatSelectColumns(sql);
|
||||
|
||||
// Add line breaks before major clauses
|
||||
result = result
|
||||
.Replace(" FROM ", "\nFROM ")
|
||||
.Replace(" WHERE ", "\nWHERE ")
|
||||
.Replace(" AND ", "\n AND ")
|
||||
@@ -104,8 +106,31 @@
|
||||
.Replace(" JOIN ", " JOIN\n ")
|
||||
.Replace(" ORDER BY ", "\nORDER BY ")
|
||||
.Replace(" GROUP BY ", "\nGROUP BY ")
|
||||
.Replace(" HAVING ", "\nHAVING ")
|
||||
.Trim();
|
||||
.Replace(" HAVING ", "\nHAVING ");
|
||||
|
||||
return result.Trim();
|
||||
}
|
||||
|
||||
private static string FormatSelectColumns(string sql)
|
||||
{
|
||||
// Find SELECT and FROM positions (case-insensitive)
|
||||
var selectIndex = sql.IndexOf("SELECT", StringComparison.OrdinalIgnoreCase);
|
||||
var fromIndex = sql.IndexOf(" FROM ", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (selectIndex < 0 || fromIndex < 0 || fromIndex <= selectIndex)
|
||||
return sql;
|
||||
|
||||
var beforeSelect = sql[..selectIndex];
|
||||
var selectKeyword = sql.Substring(selectIndex, 6); // "SELECT"
|
||||
var columnsStart = selectIndex + 6;
|
||||
var columns = sql[columnsStart..fromIndex];
|
||||
var afterColumns = sql[fromIndex..];
|
||||
|
||||
// Split columns by comma and rejoin with newlines
|
||||
var columnList = columns.Split(',');
|
||||
var formattedColumns = string.Join(",\n ", columnList.Select(c => c.Trim()));
|
||||
|
||||
return $"{beforeSelect}{selectKeyword} {formattedColumns}{afterColumns}";
|
||||
}
|
||||
|
||||
private async Task CopyToClipboard()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.Models.Enums;
|
||||
using JdeScoping.Core.Models.Search;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
using CoreSearch = JdeScoping.Core.ViewModels.SearchViewModel;
|
||||
using CoreItem = JdeScoping.Core.ViewModels.ItemViewModel;
|
||||
using CoreWorkOrder = JdeScoping.Core.ViewModels.WorkOrderViewModel;
|
||||
@@ -9,6 +10,7 @@ using CoreWorkCenter = JdeScoping.Core.ViewModels.WorkCenterViewModel;
|
||||
using CoreLot = JdeScoping.Core.ViewModels.LotViewModel;
|
||||
using CorePartOp = JdeScoping.Core.ViewModels.PartOperationViewModel;
|
||||
using CoreJdeUser = JdeScoping.Core.ViewModels.JdeUserViewModel;
|
||||
using SearchViewModel = JdeScoping.Client.Models.SearchViewModel;
|
||||
|
||||
namespace JdeScoping.Client.Extensions;
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <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);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <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();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR message for search status updates.
|
||||
/// </summary>
|
||||
public record SearchUpdate
|
||||
{
|
||||
public int Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string UserName { get; init; } = string.Empty;
|
||||
public string Status { get; init; } = string.Empty;
|
||||
public DateTime? SubmitDt { get; init; }
|
||||
public DateTime? StartDt { get; init; }
|
||||
public DateTime? EndDt { get; init; }
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR message for processor status updates.
|
||||
/// </summary>
|
||||
public record StatusUpdate
|
||||
{
|
||||
public string Message { get; init; } = string.Empty;
|
||||
public DateTime? Timestamp { get; init; }
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Client-side view model for authenticated user information.
|
||||
/// Mirrors the server-side UserInfo model returned by /api/auth/login and /api/auth/me.
|
||||
/// </summary>
|
||||
public class UserInfoViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// User's login username.
|
||||
/// </summary>
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's first name.
|
||||
/// </summary>
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's last name.
|
||||
/// </summary>
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's display name (computed on server, provided here for convenience).
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's organization title.
|
||||
/// </summary>
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's email address.
|
||||
/// </summary>
|
||||
public string EmailAddress { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -6,17 +6,17 @@ namespace JdeScoping.Client.Models;
|
||||
/// </summary>
|
||||
public class ValidCombination
|
||||
{
|
||||
public int Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public bool Timespan { get; init; }
|
||||
public bool WorkOrder { get; init; }
|
||||
public bool ItemNumber { get; init; }
|
||||
public bool ProfitCenter { get; init; }
|
||||
public bool WorkCenter { get; init; }
|
||||
public bool ComponentLot { get; init; }
|
||||
public bool Operator { get; init; }
|
||||
public bool ItemOperationMis { get; init; }
|
||||
public bool ExtractMis { get; init; }
|
||||
public int Id { get; private init; }
|
||||
public string Name { get; private init; } = string.Empty;
|
||||
public bool Timespan { get; private init; }
|
||||
public bool WorkOrder { get; private init; }
|
||||
public bool ItemNumber { get; private init; }
|
||||
public bool ProfitCenter { get; private init; }
|
||||
public bool WorkCenter { get; private init; }
|
||||
public bool ComponentLot { get; private init; }
|
||||
public bool Operator { get; private init; }
|
||||
public bool ItemOperationMis { get; private init; }
|
||||
public bool ExtractMis { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given filter flags match this combination.
|
||||
@@ -48,7 +48,7 @@ public class ValidCombination
|
||||
/// </summary>
|
||||
public static IReadOnlyList<ValidCombination> GetAll() =>
|
||||
[
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 10,
|
||||
Name = "Work Order",
|
||||
@@ -62,7 +62,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 20,
|
||||
Name = "Component Lot",
|
||||
@@ -76,7 +76,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 30,
|
||||
Name = "Time Span + Profit Center",
|
||||
@@ -90,7 +90,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 40,
|
||||
Name = "Time Span + Work Center",
|
||||
@@ -104,7 +104,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 50,
|
||||
Name = "Time Span + Operator",
|
||||
@@ -118,7 +118,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 60,
|
||||
Name = "Time Span + Profit Center + Item Number",
|
||||
@@ -132,7 +132,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 70,
|
||||
Name = "Time Span + Profit Center + Item/Operation/MIS",
|
||||
@@ -146,7 +146,7 @@ public class ValidCombination
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 80,
|
||||
Name = "Time Span + Profit Center + Work Order + Item/Operation/MIS",
|
||||
@@ -160,7 +160,7 @@ public class ValidCombination
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 90,
|
||||
Name = "Time Span + Profit Center + Extract MIS",
|
||||
@@ -174,7 +174,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = true
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 100,
|
||||
Name = "Time Span + Work Center + Item Number",
|
||||
@@ -188,7 +188,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 110,
|
||||
Name = "Time Span + Work Center + Extract MIS",
|
||||
@@ -202,7 +202,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = true
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 120,
|
||||
Name = "Time Span + Work Center + Item/Operation/MIS",
|
||||
@@ -216,7 +216,7 @@ public class ValidCombination
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 130,
|
||||
Name = "Time Span + Work Center + Work Order + Item/Operation/MIS",
|
||||
@@ -230,7 +230,7 @@ public class ValidCombination
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 140,
|
||||
Name = "Time Span + Item Number",
|
||||
@@ -244,7 +244,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 150,
|
||||
Name = "Time Span + Work Center + Operator",
|
||||
@@ -258,7 +258,7 @@ public class ValidCombination
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
new()
|
||||
{
|
||||
Id = 160,
|
||||
Name = "Time Span + Profit Center + Operator",
|
||||
|
||||
@@ -107,7 +107,7 @@ else if (_config is not null)
|
||||
<!-- Common Pipeline Info -->
|
||||
<RadzenRow Gap="1rem" class="rz-mb-4">
|
||||
<!-- Source Card -->
|
||||
<RadzenColumn Size="4">
|
||||
<RadzenColumn Size="6">
|
||||
<RadzenCard Style="height: 100%;">
|
||||
<RadzenText TextStyle="TextStyle.H6" class="rz-mb-2">Source</RadzenText>
|
||||
<p><strong>Connection:</strong>
|
||||
@@ -127,21 +127,11 @@ else if (_config is not null)
|
||||
break;
|
||||
}
|
||||
</p>
|
||||
@if (_config.Source.Parameters.Count > 0)
|
||||
{
|
||||
<p><strong>Parameters:</strong></p>
|
||||
<ul>
|
||||
@foreach (var param in _config.Source.Parameters)
|
||||
{
|
||||
<li>@param.Name (@(param.Format ?? "default"))</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</RadzenCard>
|
||||
</RadzenColumn>
|
||||
|
||||
<!-- Destination Card -->
|
||||
<RadzenColumn Size="4">
|
||||
<RadzenColumn Size="6">
|
||||
<RadzenCard Style="height: 100%;">
|
||||
<RadzenText TextStyle="TextStyle.H6" class="rz-mb-2">Destination</RadzenText>
|
||||
<p><strong>Table:</strong> @_config.Destination.Table</p>
|
||||
@@ -151,67 +141,36 @@ else if (_config is not null)
|
||||
</p>
|
||||
@if (_config.Destination.MatchColumns?.Count > 0)
|
||||
{
|
||||
<p><strong>Match Columns:</strong> @string.Join(", ", _config.Destination.MatchColumns)</p>
|
||||
<p><strong>Match Columns:</strong></p>
|
||||
<ul>
|
||||
@foreach (var col in _config.Destination.MatchColumns)
|
||||
{
|
||||
<li>@col</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
@if (_config.Destination.ExcludeFromUpdate?.Count > 0)
|
||||
{
|
||||
<p><strong>Exclude:</strong> @string.Join(", ", _config.Destination.ExcludeFromUpdate)</p>
|
||||
}
|
||||
</RadzenCard>
|
||||
</RadzenColumn>
|
||||
|
||||
<!-- Scripts Card -->
|
||||
<RadzenColumn Size="4">
|
||||
<RadzenCard Style="height: 100%;">
|
||||
<RadzenText TextStyle="TextStyle.H6" class="rz-mb-2">Scripts</RadzenText>
|
||||
<p><strong>Pre-Scripts:</strong> @_config.PreScriptCount</p>
|
||||
<p><strong>Post-Scripts:</strong> @_config.PostScriptCount</p>
|
||||
@if (_config.PreScripts?.Count > 0)
|
||||
{
|
||||
<RadzenText TextStyle="TextStyle.Subtitle2" class="rz-mt-2">Pre-Scripts:</RadzenText>
|
||||
@for (int i = 0; i < _config.PreScripts.Count; i++)
|
||||
{
|
||||
var script = _config.PreScripts[i];
|
||||
var index = i + 1;
|
||||
<div>
|
||||
<RadzenButton Text="@($"Script {index}")" Icon="code" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
|
||||
Click="@(() => ShowSqlModal($"Pre-Script {index}", script))" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@if (_config.PostScripts?.Count > 0)
|
||||
{
|
||||
<RadzenText TextStyle="TextStyle.Subtitle2" class="rz-mt-2">Post-Scripts:</RadzenText>
|
||||
@for (int i = 0; i < _config.PostScripts.Count; i++)
|
||||
{
|
||||
var script = _config.PostScripts[i];
|
||||
var index = i + 1;
|
||||
<div>
|
||||
<RadzenButton Text="@($"Script {index}")" Icon="code" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
|
||||
Click="@(() => ShowSqlModal($"Post-Script {index}", script))" />
|
||||
</div>
|
||||
}
|
||||
<p><strong>Exclude:</strong></p>
|
||||
<ul>
|
||||
@foreach (var col in _config.Destination.ExcludeFromUpdate)
|
||||
{
|
||||
<li>@col</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</RadzenCard>
|
||||
</RadzenColumn>
|
||||
</RadzenRow>
|
||||
|
||||
<!-- Schedule Sections -->
|
||||
<PipelineScheduleSection ScheduleType="UpdateTypes.Mass" Config="@_config.Schedules.Mass"
|
||||
QueryPreview="@_config.Source.MassQueryPreview" FullQuery="@_config.Source.MassQuery"
|
||||
OnViewQuery="@(q => ShowSqlModal("Mass Query", q))" />
|
||||
<PipelineScheduleSection ScheduleType="UpdateTypes.Mass" Config="@_config.Schedules.Mass" />
|
||||
|
||||
<PipelineScheduleSection ScheduleType="UpdateTypes.Daily" Config="@_config.Schedules.Daily"
|
||||
QueryPreview="@_config.Source.QueryPreview" FullQuery="@_config.Source.Query"
|
||||
OnViewQuery="@(q => ShowSqlModal("Daily Query", q))" />
|
||||
<PipelineScheduleSection ScheduleType="UpdateTypes.Daily" Config="@_config.Schedules.Daily" />
|
||||
|
||||
<PipelineScheduleSection ScheduleType="UpdateTypes.Hourly" Config="@_config.Schedules.Hourly"
|
||||
QueryPreview="@_config.Source.QueryPreview" FullQuery="@_config.Source.Query"
|
||||
OnViewQuery="@(q => ShowSqlModal("Hourly Query", q))" />
|
||||
<PipelineScheduleSection ScheduleType="UpdateTypes.Hourly" Config="@_config.Schedules.Hourly" />
|
||||
}
|
||||
|
||||
<SqlQueryModal @bind-Visible="_showSqlModal" Title="@_sqlModalTitle" Sql="@_sqlModalContent" />
|
||||
|
||||
@code {
|
||||
private List<string> _pipelineNames = [];
|
||||
private string? _selectedPipeline;
|
||||
@@ -220,10 +179,6 @@ else if (_config is not null)
|
||||
private List<PipelineScheduleStatusDto> _statuses = [];
|
||||
private List<PipelineExecutionDto> _executions = [];
|
||||
|
||||
private bool _showSqlModal;
|
||||
private string? _sqlModalTitle;
|
||||
private string? _sqlModalContent;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var result = await PipelineApi.GetPipelineNamesAsync();
|
||||
@@ -271,13 +226,6 @@ else if (_config is not null)
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSqlModal(string title, string sql)
|
||||
{
|
||||
_sqlModalTitle = $"{title} - {_selectedPipeline}";
|
||||
_sqlModalContent = sql;
|
||||
_showSqlModal = true;
|
||||
}
|
||||
|
||||
private static string FormatDuration(TimeSpan? duration)
|
||||
{
|
||||
if (!duration.HasValue) return "-";
|
||||
|
||||
@@ -74,16 +74,7 @@
|
||||
if (loginResult.Success && loginResult.User is not null)
|
||||
{
|
||||
// Notify auth state provider of successful login
|
||||
var userViewModel = new JdeScoping.Client.Models.UserInfoViewModel
|
||||
{
|
||||
Username = loginResult.User.Username,
|
||||
FirstName = loginResult.User.FirstName,
|
||||
LastName = loginResult.User.LastName,
|
||||
DisplayName = loginResult.User.DisplayName,
|
||||
EmailAddress = loginResult.User.EmailAddress,
|
||||
Title = loginResult.User.Title
|
||||
};
|
||||
_ = AuthStateProvider.MarkUserAsAuthenticated(userViewModel);
|
||||
_ = AuthStateProvider.MarkUserAsAuthenticated(loginResult.User);
|
||||
|
||||
var returnUrl = string.IsNullOrEmpty(ReturnUrl) ? "/" : ReturnUrl;
|
||||
NavigationManager.NavigateTo(returnUrl);
|
||||
|
||||
@@ -315,7 +315,7 @@ else
|
||||
await HubConnection.StartAsync();
|
||||
}
|
||||
|
||||
private void HandleSearchUpdate(SearchUpdate update)
|
||||
private void HandleSearchUpdate(SearchUpdateDto update)
|
||||
{
|
||||
if (update.Id == _search.Id)
|
||||
{
|
||||
|
||||
@@ -120,7 +120,7 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSearchUpdate(SearchUpdate update)
|
||||
private void HandleSearchUpdate(SearchUpdateDto update)
|
||||
{
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
@@ -162,7 +162,7 @@ else
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleStatusUpdate(StatusUpdate update)
|
||||
private void HandleStatusUpdate(StatusUpdateDto update)
|
||||
{
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ else
|
||||
await HubConnection.StartAsync();
|
||||
}
|
||||
|
||||
private void HandleSearchUpdate(SearchUpdate update)
|
||||
private void HandleSearchUpdate(SearchUpdateDto update)
|
||||
{
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using JdeScoping.Core.ApiContracts;
|
||||
using JdeScoping.Core.ApiContracts.Auth;
|
||||
using JdeScoping.Core.ApiContracts.Results;
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Auth;
|
||||
|
||||
namespace JdeScoping.Client.Services;
|
||||
@@ -21,6 +21,6 @@ public class AuthApiClient : ApiClientBase, IAuthApiClient
|
||||
public Task<ApiResult<Unit>> LogoutAsync(CancellationToken ct = default)
|
||||
=> PostAsync<Unit>(ApiRoutes.Auth.Logout, ct);
|
||||
|
||||
public Task<ApiResult<UserInfo>> GetCurrentUserAsync(CancellationToken ct = default)
|
||||
=> GetAsync<UserInfo>(ApiRoutes.Auth.Me, ct);
|
||||
public Task<ApiResult<UserInfoDto>> GetCurrentUserAsync(CancellationToken ct = default)
|
||||
=> GetAsync<UserInfoDto>(ApiRoutes.Auth.Me, ct);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Net.Http.Json;
|
||||
using JdeScoping.Client.Auth;
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.Models.Auth;
|
||||
|
||||
namespace JdeScoping.Client.Services;
|
||||
@@ -43,17 +42,8 @@ public class AuthService : IAuthService
|
||||
|
||||
if (result.Success && result.User is not null)
|
||||
{
|
||||
// Notify auth state provider of the login
|
||||
var userViewModel = new UserInfoViewModel
|
||||
{
|
||||
Username = result.User.Username,
|
||||
FirstName = result.User.FirstName,
|
||||
LastName = result.User.LastName,
|
||||
DisplayName = result.User.DisplayName,
|
||||
EmailAddress = result.User.EmailAddress,
|
||||
Title = result.User.Title
|
||||
};
|
||||
await _authStateProvider.MarkUserAsAuthenticated(userViewModel);
|
||||
// LoginResultModel.User is already UserInfoDto - pass directly
|
||||
await _authStateProvider.MarkUserAsAuthenticated(result.User);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.ApiContracts.SignalR;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
|
||||
@@ -13,8 +13,8 @@ public class HubConnectionService : IHubConnectionService, IAsyncDisposable
|
||||
private readonly NavigationManager _navigationManager;
|
||||
private HubConnection? _hubConnection;
|
||||
|
||||
public event Action<SearchUpdate>? OnSearchUpdate;
|
||||
public event Action<StatusUpdate>? OnStatusUpdate;
|
||||
public event Action<SearchUpdateDto>? OnSearchUpdate;
|
||||
public event Action<StatusUpdateDto>? OnStatusUpdate;
|
||||
|
||||
public bool IsConnected => _hubConnection?.State == HubConnectionState.Connected;
|
||||
|
||||
@@ -43,12 +43,12 @@ public class HubConnectionService : IHubConnectionService, IAsyncDisposable
|
||||
])
|
||||
.Build();
|
||||
|
||||
_hubConnection.On<SearchUpdate>("searchUpdate", update =>
|
||||
_hubConnection.On<SearchUpdateDto>("searchUpdate", update =>
|
||||
{
|
||||
OnSearchUpdate?.Invoke(update);
|
||||
});
|
||||
|
||||
_hubConnection.On<StatusUpdate>("statusUpdate", update =>
|
||||
_hubConnection.On<StatusUpdateDto>("statusUpdate", update =>
|
||||
{
|
||||
OnStatusUpdate?.Invoke(update);
|
||||
});
|
||||
@@ -92,7 +92,7 @@ public class HubConnectionService : IHubConnectionService, IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<StatusUpdate?> GetCachedStatusAsync()
|
||||
public async Task<StatusUpdateDto?> GetCachedStatusAsync()
|
||||
{
|
||||
if (_hubConnection == null || _hubConnection.State != HubConnectionState.Connected)
|
||||
{
|
||||
@@ -101,7 +101,7 @@ public class HubConnectionService : IHubConnectionService, IAsyncDisposable
|
||||
|
||||
try
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<StatusUpdate>("GetCachedStatus");
|
||||
return await _hubConnection.InvokeAsync<StatusUpdateDto>("GetCachedStatus");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using JdeScoping.Client.Models;
|
||||
using JdeScoping.Core.ApiContracts.SignalR;
|
||||
|
||||
namespace JdeScoping.Client.Services;
|
||||
|
||||
@@ -10,12 +10,12 @@ public interface IHubConnectionService
|
||||
/// <summary>
|
||||
/// Event fired when a search update is received.
|
||||
/// </summary>
|
||||
event Action<SearchUpdate>? OnSearchUpdate;
|
||||
event Action<SearchUpdateDto>? OnSearchUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when a processor status update is received.
|
||||
/// </summary>
|
||||
event Action<StatusUpdate>? OnStatusUpdate;
|
||||
event Action<StatusUpdateDto>? OnStatusUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Starts the SignalR connection.
|
||||
@@ -30,7 +30,7 @@ public interface IHubConnectionService
|
||||
/// <summary>
|
||||
/// Gets the cached processor status from the server.
|
||||
/// </summary>
|
||||
Task<StatusUpdate?> GetCachedStatusAsync();
|
||||
Task<StatusUpdateDto?> GetCachedStatusAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current connection state.
|
||||
|
||||
@@ -21,5 +21,7 @@
|
||||
@using JdeScoping.Client.Models
|
||||
@using JdeScoping.Client.Pages
|
||||
@using JdeScoping.Client.Services
|
||||
@using JdeScoping.Core.ApiContracts.Auth
|
||||
@using JdeScoping.Core.ApiContracts.SignalR
|
||||
@using JdeScoping.Core.ViewModels
|
||||
@using ClientSearchViewModel = JdeScoping.Client.Models.SearchViewModel
|
||||
|
||||
Reference in New Issue
Block a user