diff --git a/NEW/src/JdeScoping.Client/Components/Admin/PipelineScheduleSection.razor b/NEW/src/JdeScoping.Client/Components/Admin/PipelineScheduleSection.razor new file mode 100644 index 0000000..3e5a23a --- /dev/null +++ b/NEW/src/JdeScoping.Client/Components/Admin/PipelineScheduleSection.razor @@ -0,0 +1,92 @@ +@namespace JdeScoping.Client.Components.Admin +@using JdeScoping.Core.ApiContracts.Pipelines +@using JdeScoping.Core.Models.Enums + + + + + + @GetScheduleTypeName(ScheduleType) Refresh + + + + @if (Config?.Enabled == true) + { + + } + else + { + + } + + + + @if (Config is not null) + { + Schedule Settings + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingValueSource
Interval@FormatInterval(Config.IntervalMinutes)@(Config.IntervalIsOverride ? "Override" : "Default")
Pre-Purge@(Config.PrePurge ? "Yes" : "No")@(Config.PrePurgeIsOverride ? "Override" : "Default")
Re-Index@(Config.ReIndex ? "Yes" : "No")@(Config.ReIndexIsOverride ? "Override" : "Default")
+ + @if (!string.IsNullOrWhiteSpace(QueryPreview)) + { + Query +
+ @QueryPreview +
+ @if (!string.IsNullOrWhiteSpace(FullQuery)) + { + + } + } + } +
+ +@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 OnViewQuery { get; set; } + + private static string GetScheduleTypeName(UpdateTypes type) => type switch + { + UpdateTypes.Mass => "Mass", + UpdateTypes.Daily => "Daily", + UpdateTypes.Hourly => "Hourly", + _ => type.ToString() + }; + + private static string FormatInterval(int minutes) + { + if (minutes >= 1440) + return $"{minutes / 1440} day(s) ({minutes} min)"; + if (minutes >= 60) + return $"{minutes / 60} hour(s) ({minutes} min)"; + return $"{minutes} minutes"; + } +} diff --git a/NEW/src/JdeScoping.Client/Components/Admin/SqlQueryModal.razor b/NEW/src/JdeScoping.Client/Components/Admin/SqlQueryModal.razor new file mode 100644 index 0000000..9f69f13 --- /dev/null +++ b/NEW/src/JdeScoping.Client/Components/Admin/SqlQueryModal.razor @@ -0,0 +1,123 @@ +@namespace JdeScoping.Client.Components.Admin +@inject IJSRuntime JS + +@if (Visible) +{ +
+
+
+ @Title + +
+
+
@FormattedSql
+
+ +
+
+} + + + +@code { + [Parameter] public bool Visible { get; set; } + [Parameter] public EventCallback VisibleChanged { get; set; } + [Parameter] public string? Title { get; set; } + [Parameter] public string? Sql { get; set; } + + private string FormattedSql => FormatSql(Sql); + + private static string FormatSql(string? sql) + { + if (string.IsNullOrWhiteSpace(sql)) + return ""; + + // Basic SQL formatting - add line breaks before major clauses + return sql + .Replace(" SELECT ", "\nSELECT ") + .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 ") + .Trim(); + } + + private async Task CopyToClipboard() + { + if (!string.IsNullOrWhiteSpace(Sql)) + { + await JS.InvokeVoidAsync("navigator.clipboard.writeText", Sql); + } + } + + private async Task Close() + { + await VisibleChanged.InvokeAsync(false); + } +} diff --git a/NEW/src/JdeScoping.Client/Program.cs b/NEW/src/JdeScoping.Client/Program.cs index be40a6b..8a2f973 100644 --- a/NEW/src/JdeScoping.Client/Program.cs +++ b/NEW/src/JdeScoping.Client/Program.cs @@ -54,5 +54,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); await builder.Build().RunAsync(); diff --git a/NEW/src/JdeScoping.Client/Services/PipelineApiClient.cs b/NEW/src/JdeScoping.Client/Services/PipelineApiClient.cs new file mode 100644 index 0000000..19e46a7 --- /dev/null +++ b/NEW/src/JdeScoping.Client/Services/PipelineApiClient.cs @@ -0,0 +1,25 @@ +using JdeScoping.Core.ApiContracts; +using JdeScoping.Core.ApiContracts.Pipelines; +using JdeScoping.Core.ApiContracts.Results; + +namespace JdeScoping.Client.Services; + +/// +/// HTTP client implementation for pipeline configuration API. +/// +public class PipelineApiClient : ApiClientBase, IPipelineApiClient +{ + public PipelineApiClient(HttpClient httpClient) : base(httpClient) { } + + public Task> GetPipelineNamesAsync(CancellationToken ct = default) + => GetAsync(ApiRoutes.Pipelines.Base, ct); + + public Task> GetPipelineAsync(string name, CancellationToken ct = default) + => GetAsync(ApiRoutes.Pipelines.GetByName(name), ct); + + public Task> GetStatusAsync(string name, CancellationToken ct = default) + => GetAsync(ApiRoutes.Pipelines.GetStatus(name), ct); + + public Task> GetExecutionsAsync(string name, int count = 30, CancellationToken ct = default) + => GetAsync(ApiRoutes.Pipelines.GetExecutions(name, count), ct); +} diff --git a/NEW/src/JdeScoping.Client/_Imports.razor b/NEW/src/JdeScoping.Client/_Imports.razor index 285e41b..d336ab8 100644 --- a/NEW/src/JdeScoping.Client/_Imports.razor +++ b/NEW/src/JdeScoping.Client/_Imports.razor @@ -13,6 +13,7 @@ @using Radzen.Blazor @using JdeScoping.Client @using JdeScoping.Client.Auth +@using JdeScoping.Client.Components.Admin @using JdeScoping.Client.Components.FilterPanels @using JdeScoping.Client.Extensions @using JdeScoping.Client.Components.Shared diff --git a/NEW/src/JdeScoping.Core/ApiContracts/IPipelineApiClient.cs b/NEW/src/JdeScoping.Core/ApiContracts/IPipelineApiClient.cs new file mode 100644 index 0000000..e1ba6f5 --- /dev/null +++ b/NEW/src/JdeScoping.Core/ApiContracts/IPipelineApiClient.cs @@ -0,0 +1,22 @@ +using JdeScoping.Core.ApiContracts.Pipelines; +using JdeScoping.Core.ApiContracts.Results; + +namespace JdeScoping.Core.ApiContracts; + +/// +/// Client contract for pipeline configuration API operations. +/// +public interface IPipelineApiClient +{ + /// Gets list of all available pipeline names. + Task> GetPipelineNamesAsync(CancellationToken ct = default); + + /// Gets configuration for a specific pipeline. + Task> GetPipelineAsync(string name, CancellationToken ct = default); + + /// Gets schedule status for a pipeline. + Task> GetStatusAsync(string name, CancellationToken ct = default); + + /// Gets recent execution history for a pipeline. + Task> GetExecutionsAsync(string name, int count = 30, CancellationToken ct = default); +}