Files
GoMFT/components/job_run_details.templ
T
StarFleetCPTN 49a586db53 feat: Update dependencies and enhance admin role management
- Upgraded `golang.org/x/crypto` to v0.36.0 and other indirect dependencies to their latest versions.
- Added functionality to assign admin roles to users upon creation in the main application logic.
- Introduced new templates for admin role management, including forms for creating and editing roles.
- Removed deprecated admin tools template to streamline the admin interface.
- Added audit logging for role changes to improve tracking and accountability.
2025-03-22 16:55:36 -07:00

202 lines
9.0 KiB
Templ

package components
import (
"context"
"fmt"
"github.com/starfleetcptn/gomft/internal/db"
"time"
)
type JobRunDetailsData struct {
JobHistory db.JobHistory
Job db.Job
Config db.TransferConfig
}
templ JobRunDetails(ctx context.Context, data JobRunDetailsData) {
@LayoutWithContext("Job Run Details", ctx) {
@JobRunDetailsContent(ctx, data)
}
}
// JobRunDetailsContent is the same as JobRunDetails but without the layout wrapper
// This is used for testing
templ JobRunDetailsContent(ctx context.Context, data JobRunDetailsData) {
<div class="py-6 px-4 mx-auto max-w-7xl lg:px-8">
<div class="mb-6">
<a href="/dashboard" class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 inline-flex items-center">
<i class="fas fa-arrow-left mr-2"></i> Back to Dashboard
</a>
</div>
<div class="flex items-center justify-between mb-8">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white flex items-center">
<i class="fas fa-file-alt mr-3 text-blue-600 dark:text-blue-400"></i>
Job Run Details
</h1>
</div>
<!-- Job Run Information Card -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm mb-8">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">{ data.Job.Name }</h3>
if data.JobHistory.Status == "completed" {
<span class="px-3 py-1 text-sm font-medium rounded-full bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-300 inline-flex items-center">
<i class="fas fa-check mr-2"></i> Completed
</span>
} else if data.JobHistory.Status == "failed" {
<span class="px-3 py-1 text-sm font-medium rounded-full bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-300 inline-flex items-center">
<i class="fas fa-times mr-2"></i> Failed
</span>
} else {
<span class="px-3 py-1 text-sm font-medium rounded-full bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-300 inline-flex items-center">
<i class="fas fa-spinner fa-spin mr-2"></i> Running
</span>
}
</div>
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">Config: { data.Config.Name }</p>
</div>
<div class="px-4 py-5 sm:p-6">
<dl class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-2 lg:grid-cols-3">
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center mb-1">
<i class="fas fa-calendar-alt mr-2 text-gray-400 dark:text-gray-500"></i> Start Time
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
{ data.JobHistory.StartTime.Format("Jan 02, 2006 15:04:05") }
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center mb-1">
<i class="fas fa-calendar-check mr-2 text-gray-400 dark:text-gray-500"></i> End Time
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
if data.JobHistory.EndTime != nil {
{ data.JobHistory.EndTime.Format("Jan 02, 2006 15:04:05") }
} else {
<span class="italic text-gray-500 dark:text-gray-400">In progress</span>
}
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center mb-1">
<i class="fas fa-clock mr-2 text-gray-400 dark:text-gray-500"></i> Duration
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
if data.JobHistory.EndTime != nil {
{ data.JobHistory.EndTime.Sub(data.JobHistory.StartTime).String() }
} else {
<span class="italic text-gray-500 dark:text-gray-400">In progress</span>
}
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center mb-1">
<i class="fas fa-upload mr-2 text-gray-400 dark:text-gray-500"></i> Data Transferred
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
{ formatBytes(data.JobHistory.BytesTransferred) }
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center mb-1">
<i class="fas fa-file mr-2 text-gray-400 dark:text-gray-500"></i> Files Transferred
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
{ fmt.Sprintf("%d files", data.JobHistory.FilesTransferred) }
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 flex items-center mb-1">
<i class="fas fa-calendar-day mr-2 text-gray-400 dark:text-gray-500"></i> Job Schedule
</dt>
<dd class="text-sm text-gray-900 dark:text-white">
{ data.Job.Schedule }
</dd>
</div>
</dl>
</div>
</div>
<!-- Transfer Configuration Details -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm mb-8">
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700">
<h3 class="text-lg font-medium text-gray-900 dark:text-white flex items-center">
<i class="fas fa-cog mr-3 text-blue-600 dark:text-blue-400"></i>
Transfer Configuration
</h3>
</div>
<div class="px-4 py-5 sm:p-6">
<dl class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-2">
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Source Type</dt>
<dd class="text-sm text-gray-900 dark:text-white">
<span class="px-2.5 py-0.5 text-xs font-medium rounded bg-gray-100 dark:bg-gray-700">{ data.Config.SourceType }</span>
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Destination Type</dt>
<dd class="text-sm text-gray-900 dark:text-white">
<span class="px-2.5 py-0.5 text-xs font-medium rounded bg-gray-100 dark:bg-gray-700">{ data.Config.DestinationType }</span>
</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Source Path</dt>
<dd class="text-sm text-gray-900 dark:text-white font-mono bg-gray-50 dark:bg-gray-900 p-2 rounded-lg border border-gray-200 dark:border-gray-700">{ data.Config.SourcePath }</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">Destination Path</dt>
<dd class="text-sm text-gray-900 dark:text-white font-mono bg-gray-50 dark:bg-gray-900 p-2 rounded-lg border border-gray-200 dark:border-gray-700">{ data.Config.DestinationPath }</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">File Pattern</dt>
<dd class="text-sm text-gray-900 dark:text-white font-mono">{ data.Config.FilePattern }</dd>
</div>
</dl>
</div>
</div>
<!-- Error Information (if any) -->
if data.JobHistory.Status == "failed" && data.JobHistory.ErrorMessage != "" {
<div class="p-4 mb-8 text-red-800 border-l-4 border-red-300 bg-red-50 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800 rounded-lg">
<div class="flex items-center mb-2">
<i class="fas fa-exclamation-triangle flex-shrink-0 mr-2 text-red-600 dark:text-red-500"></i>
<h3 class="text-lg font-medium">Error Information</h3>
</div>
<div class="mt-2">
<pre class="text-sm whitespace-pre-wrap font-mono p-3 bg-white dark:bg-gray-900 rounded-lg border border-red-200 dark:border-red-800">{ data.JobHistory.ErrorMessage }</pre>
</div>
</div>
}
<!-- Action Buttons -->
<div class="flex flex-col sm:flex-row gap-4 mt-8">
<a href="/jobs" class="text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700 inline-flex items-center justify-center">
<i class="fas fa-list-ul mr-2"></i> View All Jobs
</a>
<a href={ templ.SafeURL(fmt.Sprintf("/jobs/%d", data.Job.ID)) } class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 inline-flex items-center justify-center">
<i class="fas fa-edit mr-2"></i> Edit Job
</a>
</div>
</div>
}
// formatDuration formats a duration in a human-readable way
func formatDuration(d time.Duration) string {
d = d.Round(time.Second)
h := d / time.Hour
d -= h * time.Hour
m := d / time.Minute
d -= m * time.Minute
s := d / time.Second
if h > 0 {
return fmt.Sprintf("%dh %dm %ds", h, m, s)
}
if m > 0 {
return fmt.Sprintf("%dm %ds", m, s)
}
return fmt.Sprintf("%ds", s)
}