06-12-2022

This commit is contained in:
Jonathan Jenne
2022-12-06 14:08:20 +01:00
parent c867e4e3a6
commit 248be23804
47 changed files with 1521 additions and 355 deletions

View File

@@ -1,7 +1,7 @@
@page "/history"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Data;
@inject ApiService Api
@inject DashboardService Api
<PageTitle>History</PageTitle>
@@ -41,18 +41,18 @@ else
protected async override void OnInitialized()
{
ApiStatusResponse data = await Api.GetData();
DashboardResponse data = await Api.GetData();
UpdateData(data);
Api.DataUpdated += Api_DataUpdated;
}
protected void Api_DataUpdated(object sender, ApiStatusResponse e)
protected void Api_DataUpdated(object sender, DashboardResponse e)
{
UpdateData(e);
}
protected void UpdateData(ApiStatusResponse response)
protected void UpdateData(DashboardResponse response)
{
today = response.heartbeat;
historyEntries = response.jobHistory;

View File

@@ -0,0 +1,28 @@
@page "/jobs/{jobId:int}/edit"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Data;
@using ECM.JobRunner.Web.Components.Job;
@inject NavigationManager Navigation;
@inject JobService Jobs;
<PageTitle>Job bearbeiten</PageTitle>
<h3>Job bearbeiten</h3>
<JobForm JobId="JobId" OnValidSubmit="OnFormSubmit" />
@code {
[Parameter]
public int JobId { get; set; }
private async void OnFormSubmit(EditContext ctx)
{
JobDefinition job = (JobDefinition)ctx.Model;
bool result = await Jobs.UpdateJob(job);
if (result == true)
{
Navigation.NavigateTo($"/jobs/{job.Id}");
}
}
}

View File

@@ -0,0 +1,76 @@
@page "/jobs"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Data;
@inject JobService Jobs
<PageTitle>Jobs</PageTitle>
<h3>Jobs</h3>
@if (jobs == null)
{
<ul class="list-group">
<li class="list-group-item">Loading Jobs..</li>
</ul>
}
else
{
<div class="list-group">
@foreach (var job in jobs)
{
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-start" href="/jobs/@job.Id">
<div class="ms-2 me-auto">
<div class="fw-bold">
<span>
@if (job.Active)
{
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-play-circle text-success" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M6.271 5.055a.5.5 0 0 1 .52.038l3.5 2.5a.5.5 0 0 1 0 .814l-3.5 2.5A.5.5 0 0 1 6 10.5v-5a.5.5 0 0 1 .271-.445z" />
</svg>
}
else
{
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stop-circle text-danger" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M5 6.5A1.5 1.5 0 0 1 6.5 5h3A1.5 1.5 0 0 1 11 6.5v3A1.5 1.5 0 0 1 9.5 11h-3A1.5 1.5 0 0 1 5 9.5v-3z" />
</svg>
}
</span>
<span>@job.Name</span>
</div>
@job.Type.Name
</div>
@if (job.Active)
{
<span class="badge bg-primary rounded-pill">Running</span>
}
else
{
<span class="badge bg-danger rounded-pill">Stopped</span>
}
</a>
}
</div>
<div class="btn-group mt-3" role="group" aria-label="Basic example">
<a class="btn btn-primary" href="jobs/new">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg> New
</a>
</div>
}
@code {
private List<JobDefinition>? jobs;
protected async override void OnInitialized()
{
jobs = await Jobs.GetJobs();
StateHasChanged();
}
}

View File

@@ -1,7 +1,10 @@
@page "/jobs/{jobId:int}"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Data;
@inject ApiService Api
@inject NavigationManager Navigation;
@inject IJSRuntime JsRuntime
@inject JobService Jobs
<PageTitle>Job</PageTitle>
@@ -49,7 +52,7 @@ else
<path d="M2 1.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1h-11a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1-.5-.5zm2.5.5v1a3.5 3.5 0 0 0 1.989 3.158c.533.256 1.011.791 1.011 1.491v.702c0 .7-.478 1.235-1.011 1.491A3.5 3.5 0 0 0 4.5 13v1h7v-1a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351v-.702c0-.7.478-1.235 1.011-1.491A3.5 3.5 0 0 0 11.5 3V2h-7z" />
</svg> Next Run at
</div>
@DateTime.Now.AddMinutes(5)
@nextExecution
</div>
</li>
</ul>
@@ -66,7 +69,7 @@ else
<path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z" />
</svg> Edit
</a>
<a class="btn btn-danger">
<a class="btn btn-danger" @onclick="DeleteJob">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash3" viewBox="0 0 16 16">
<path d="M6.5 1h3a.5.5 0 0 1 .5.5v1H6v-1a.5.5 0 0 1 .5-.5ZM11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3A1.5 1.5 0 0 0 5 1.5v1H2.506a.58.58 0 0 0-.01 0H1.5a.5.5 0 0 0 0 1h.538l.853 10.66A2 2 0 0 0 4.885 16h6.23a2 2 0 0 0 1.994-1.84l.853-10.66h.538a.5.5 0 0 0 0-1h-.995a.59.59 0 0 0-.01 0H11Zm1.958 1-.846 10.58a1 1 0 0 1-.997.92h-6.23a1 1 0 0 1-.997-.92L3.042 3.5h9.916Zm-7.487 1a.5.5 0 0 1 .528.47l.5 8.5a.5.5 0 0 1-.998.06L5 5.03a.5.5 0 0 1 .47-.53Zm5.058 0a.5.5 0 0 1 .47.53l-.5 8.5a.5.5 0 1 1-.998-.06l.5-8.5a.5.5 0 0 1 .528-.47ZM8 4.5a.5.5 0 0 1 .5.5v8.5a.5.5 0 0 1-1 0V5a.5.5 0 0 1 .5-.5Z" />
</svg> Delete
@@ -79,15 +82,31 @@ else
public int JobId { get; set; }
private JobDefinition? job;
private DateTime nextExecution;
protected async override void OnInitialized()
{
var jobs = await Api.GetJobList();
job = await Jobs.GetJob(JobId);
if (jobs != null)
{
job = jobs.Where(j => j.Id == JobId).SingleOrDefault();
if (job != null)
{
nextExecution = Jobs.GetNextExecutionTime(job.CronSchedule);
StateHasChanged();
}
}
protected async void DeleteJob()
{
if (job != null)
{
bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Are you sure?");
if (confirmed)
{
await Jobs.DeleteJob(job);
Navigation.NavigateTo($"/jobs");
}
}
}
}

View File

@@ -0,0 +1,28 @@
@page "/jobs/new"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Data;
@using ECM.JobRunner.Web.Components.Job;
@inject NavigationManager Navigation;
@inject JobService Jobs;
<PageTitle>Job erstellen</PageTitle>
<h3>Job erstellen</h3>
<JobForm JobId="JobId" OnValidSubmit="OnFormSubmit" />
@code {
public int JobId = -1;
private async void OnFormSubmit(EditContext ctx)
{
JobDefinition job = (JobDefinition)ctx.Model;
bool result = await Jobs.CreateJob(job);
if (result == true)
{
Navigation.NavigateTo($"/jobs");
}
}
}

View File

@@ -1,5 +0,0 @@
<h3>JobForm</h3>
@code {
}

View File

@@ -1,42 +0,0 @@
@page "/jobs"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Data;
@inject ApiService Api
<PageTitle>Jobs</PageTitle>
<h3>Jobs</h3>
@if (jobList == null)
{
<ul class="list-group">
<li class="list-group-item">Loading Jobs..</li>
</ul>
}
else
{
<div class="list-group">
@foreach (var job in jobList)
{
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-start" href="/jobs/@job.Id">
<div class="ms-2 me-auto">
<div class="fw-bold">
<span>@job.Name</span>
</div>
@job.Type.Name
</div>
<span class="badge bg-primary rounded-pill">Now</span>
</a>
}
</div>
}
@code {
private List<JobDefinition>? jobList;
protected async override void OnInitialized()
{
jobList = await Api.GetJobList();
StateHasChanged();
}
}

View File

@@ -1,7 +0,0 @@
<PageTitle>New Job</PageTitle>
<h3>New Job</h3>
@code {
}

View File

@@ -0,0 +1,135 @@
@page "/status"
@using ECM.JobRunner.Common.JobRunnerReference;
@using ECM.JobRunner.Web.Components.Status;
@using ECM.JobRunner.Web.Data;
@inject DashboardService Api
<PageTitle>Status</PageTitle>
<h3 class="mb-3">Job Status</h3>
<section class="mb-5">
@if (executingEntries == null)
{
<h4>Executing</h4>
<ul class="list-group">
<li class="list-group-item">Loading Job Status..</li>
</ul>
}
else if (executingEntries.Count == 0)
{
<h4>Executing</h4>
<ul class="list-group">
<li class="list-group-item">No jobs currently executing</li>
</ul>
}
else
{
<h4>Executing (@executingEntries.Count)</h4>
<ul class="list-group">
@foreach (var entry in executingEntries)
{
<li class="list-group-item">
<div class="d-flex justify-content-between align-items-start mb-3">
<div class="ms-2 me-auto w-100">
<div class="fw-bold">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-circle text-success" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M10.97 4.97a.235.235 0 0 0-.02.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05z" />
</svg>
<span>@entry.Name</span>
</div>
</div>
<span class="badge bg-primary rounded-pill">Started @entry.StartTime.ToLongTimeString()</span>
</div>
<Progress jobStatus="entry" />
</li>
}
</ul>
}
</section>
@if (completedEntries == null)
{
<h4>Completed</h4>
<ul class="list-group">
<li class="list-group-item">Loading Job Status..</li>
</ul>
}
else if (completedEntries.Count == 0)
{
<h4>Completed</h4>
<ul class="list-group">
<li class="list-group-item">No jobs currently executing</li>
</ul>
}
else
{
<h4>Completed (@completedEntries.Count)</h4>
<ul class="list-group">
@foreach (var entry in completedEntries)
{
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto w-100">
<div class="fw-bold">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-circle text-success" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M10.97 4.97a.235.235 0 0 0-.02.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05z" />
</svg>
<span>@entry.Name</span>
</div>
<ul>
<li>Execution Time: @((int)entry.ExecutionTime.TotalSeconds)s</li>
<li>Started: @entry.StartTime.ToLongTimeString()</li>
<li>Completed: @entry.CompleteTime.ToLongTimeString()</li>
</ul>
</div>
<span class="badge bg-primary rounded-pill">Completed @entry.CompleteTime.ToLongTimeString()</span>
</li>
}
</ul>
}
@code {
private DateTime today;
private List<StatusItem>? executingEntries;
private List<StatusItem>? completedEntries;
protected async override void OnInitialized()
{
DashboardResponse data = await Api.GetData();
UpdateData(data);
Api.DataUpdated += Api_DataUpdated;
}
protected void Api_DataUpdated(object sender, DashboardResponse e)
{
UpdateData(e);
}
protected void UpdateData(DashboardResponse response)
{
today = response.heartbeat;
executingEntries = response.jobStatus.
Where(s => s.ProgressTotal > 0).
Where(s => s.Executing).
ToList();
completedEntries = response.jobStatus.
Where(s => !s.Executing).
Where(s => s.StartTime.AddMinutes(1) > DateTime.Now).
ToList();
InvokeAsync(StateHasChanged);
}
}