From dc927e2f71069e7e7fa57f3450188b466e0ba42a Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 7 Jan 2026 08:18:57 -0500 Subject: [PATCH] feat(client): add PipelineViewer page Add admin page for viewing ETL pipeline configurations with: - Pipeline selector dropdown (alphabetical list) - Status summary table (type, last run, success, next required, status) - Execution history table with paging (10 per page) - Source, destination, and scripts info cards - Three PipelineScheduleSection components for Mass, Daily, Hourly schedules - SQL modal integration for viewing queries and scripts --- .../Pages/Admin/PipelineViewer.razor | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 NEW/src/JdeScoping.Client/Pages/Admin/PipelineViewer.razor diff --git a/NEW/src/JdeScoping.Client/Pages/Admin/PipelineViewer.razor b/NEW/src/JdeScoping.Client/Pages/Admin/PipelineViewer.razor new file mode 100644 index 0000000..a72a552 --- /dev/null +++ b/NEW/src/JdeScoping.Client/Pages/Admin/PipelineViewer.razor @@ -0,0 +1,289 @@ +@page "/admin/pipeline-viewer" +@attribute [Authorize] +@using JdeScoping.Core.ApiContracts +@using JdeScoping.Core.ApiContracts.Pipelines +@using JdeScoping.Core.Models.Enums +@inject IPipelineApiClient PipelineApi + +Pipeline Configuration Viewer - JDE Scoping Tool + +ETL Pipeline Configuration Viewer + + + + + + + + +@if (_isLoading) +{ + +} +else if (_config is not null) +{ + + + Schedule Status Summary + + + + + + + + + + + + + + + + + + + + + + + + Recent Execution History + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Source +

Connection: + @switch (_config.Source.Connection.ToLower()) + { + case "jde": + + break; + case "cms": + + break; + case "giw": + + break; + default: + + break; + } +

+ @if (_config.Source.Parameters.Count > 0) + { +

Parameters:

+
    + @foreach (var param in _config.Source.Parameters) + { +
  • @param.Name (@(param.Format ?? "default"))
  • + } +
+ } +
+
+ + + + + Destination +

Table: @_config.Destination.Table

+

Operation: + +

+ @if (_config.Destination.MatchColumns?.Count > 0) + { +

Match Columns: @string.Join(", ", _config.Destination.MatchColumns)

+ } + @if (_config.Destination.ExcludeFromUpdate?.Count > 0) + { +

Exclude: @string.Join(", ", _config.Destination.ExcludeFromUpdate)

+ } +
+
+ + + + + Scripts +

Pre-Scripts: @_config.PreScriptCount

+

Post-Scripts: @_config.PostScriptCount

+ @if (_config.PreScripts?.Count > 0) + { + Pre-Scripts: + @for (int i = 0; i < _config.PreScripts.Count; i++) + { + var script = _config.PreScripts[i]; + var index = i + 1; +
+ +
+ } + } + @if (_config.PostScripts?.Count > 0) + { + Post-Scripts: + @for (int i = 0; i < _config.PostScripts.Count; i++) + { + var script = _config.PostScripts[i]; + var index = i + 1; +
+ +
+ } + } +
+
+
+ + + + + + + +} + + + +@code { + private List _pipelineNames = []; + private string? _selectedPipeline; + private bool _isLoading; + private PipelineConfigDto? _config; + private List _statuses = []; + private List _executions = []; + + private bool _showSqlModal; + private string? _sqlModalTitle; + private string? _sqlModalContent; + + protected override async Task OnInitializedAsync() + { + var result = await PipelineApi.GetPipelineNamesAsync(); + if (result.IsSuccess) + { + _pipelineNames = result.Value.PipelineNames; + } + } + + private async Task OnPipelineChanged() + { + if (string.IsNullOrWhiteSpace(_selectedPipeline)) + { + _config = null; + _statuses = []; + _executions = []; + return; + } + + _isLoading = true; + try + { + var configTask = PipelineApi.GetPipelineAsync(_selectedPipeline); + var statusTask = PipelineApi.GetStatusAsync(_selectedPipeline); + var executionsTask = PipelineApi.GetExecutionsAsync(_selectedPipeline); + + await Task.WhenAll(configTask, statusTask, executionsTask); + + var configResult = configTask.Result; + var statusResult = statusTask.Result; + var executionsResult = executionsTask.Result; + + if (configResult.IsSuccess) + _config = configResult.Value; + + if (statusResult.IsSuccess) + _statuses = statusResult.Value.Statuses; + + if (executionsResult.IsSuccess) + _executions = executionsResult.Value.Executions; + } + finally + { + _isLoading = false; + } + } + + private void ShowSqlModal(string title, string sql) + { + _sqlModalTitle = $"{title} - {_selectedPipeline}"; + _sqlModalContent = sql; + _showSqlModal = true; + } + + private static string FormatDuration(TimeSpan? duration) + { + if (!duration.HasValue) return "-"; + var d = duration.Value; + if (d.TotalHours >= 1) return $"{d.Hours}h {d.Minutes}m"; + if (d.TotalMinutes >= 1) return $"{d.Minutes}m {d.Seconds}s"; + return $"{d.Seconds}s"; + } +}