feat(frontend): streamline job creation actions

This commit is contained in:
2026-06-21 02:19:30 +03:30
parent 55d8ef8290
commit 97eb42f3dc
2 changed files with 44 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
import { Plus, RotateCcw } from "lucide-react";
import { Eye, Plus, RotateCcw } from "lucide-react";
import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import { Link } from "react-router-dom";
import { toast } from "sonner";
@@ -93,6 +93,7 @@ export function JobsPage() {
max_attempts: nextMaxAttempts
});
await refresh();
setCreateOpen(false);
toast.success("Demo job created.");
} catch (caught) {
toast.error(caught instanceof Error ? caught.message : String(caught));
@@ -115,6 +116,7 @@ export function JobsPage() {
try {
await Promise.all(batch.map(([type, nextPriority]) => api.createJob({ type, payload: demoPayload(type), priority: nextPriority, max_attempts: 3 })));
await refresh();
setCreateOpen(false);
toast.success("Batch created.");
} catch (caught) {
toast.error(caught instanceof Error ? caught.message : String(caught));
@@ -135,29 +137,6 @@ export function JobsPage() {
</button>
</header>
<section className="panel">
<div className="row-actions">
<button type="button" onClick={() => void createDemo("demo.success", 60)}>
Success
</button>
<button type="button" onClick={() => void createDemo("demo.fail", 50, 2)}>
Failing
</button>
<button type="button" onClick={() => void createDemo("demo.slow", 80)}>
Slow
</button>
<button type="button" onClick={() => void createDemo("demo.timeout", 70, 2)}>
Timeout
</button>
<button type="button" onClick={() => void createDemo("demo.flaky", 75, 3)}>
Flaky Retry
</button>
<button type="button" onClick={() => void createBatch()}>
<RotateCcw size={16} /> 10 Mixed
</button>
</div>
</section>
<section className="panel">
<div className="toolbar">
<SelectField value={statusFilter} options={statusOptions} onChange={(value) => setStatusFilter(value as JobStatus | "all")} />
@@ -182,7 +161,9 @@ export function JobsPage() {
<td>
<StatusBadge status={job.status} />
</td>
<td>{job.type}</td>
<td>
<code className="inline-code">{job.type}</code>
</td>
<td>{job.priority}</td>
<td>
{job.attempts}/{job.max_attempts}
@@ -192,8 +173,8 @@ export function JobsPage() {
</td>
<td>{job.locked_by ?? "-"}</td>
<td>
<Link className="secondary-button" to={`/jobs/${job.id}`}>
Detail
<Link className="icon-button" aria-label={`view ${job.type}`} title="View job" to={`/jobs/${job.id}`}>
<Eye size={18} />
</Link>
</td>
</tr>
@@ -207,6 +188,26 @@ export function JobsPage() {
{createOpen && (
<Modal title="Create Job" onClose={() => setCreateOpen(false)}>
<form className="modal-form" onSubmit={createJob}>
<div className="preset-grid">
<button className="secondary-button" type="button" onClick={() => setType("demo.success")}>
Success
</button>
<button className="secondary-button" type="button" onClick={() => setType("demo.fail")}>
Failing
</button>
<button className="secondary-button" type="button" onClick={() => setType("demo.slow")}>
Slow
</button>
<button className="secondary-button" type="button" onClick={() => setType("demo.timeout")}>
Timeout
</button>
<button className="secondary-button" type="button" onClick={() => setType("demo.flaky")}>
Flaky Retry
</button>
<button className="secondary-button" type="button" onClick={() => void createBatch()}>
<RotateCcw size={16} /> 10 Mixed
</button>
</div>
<SelectField label="Job type" value={jobType} options={jobTypeOptions} onChange={setType} />
<JsonField label="Payload JSON" value={payload} onChange={setPayload} />
<label>
@@ -226,6 +227,9 @@ export function JobsPage() {
<input value={idempotencyKey} onChange={(event) => setIdempotencyKey(event.target.value)} />
</label>
<div className="modal-actions">
<button className="secondary-button" type="button" onClick={() => void createDemo(jobType, priority, maxAttempts)}>
Quick Create
</button>
<button className="secondary-button" type="button" onClick={() => setCreateOpen(false)}>
Cancel
</button>

View File

@@ -992,6 +992,12 @@ code {
text-overflow: ellipsis;
}
.inline-code {
max-width: 100%;
padding: 4px 7px;
white-space: nowrap;
}
.action-grid {
display: grid;
gap: 8px;
@@ -1004,6 +1010,12 @@ code {
gap: 8px;
}
.preset-grid {
display: grid;
gap: 8px;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.checkbox-row {
align-items: center;
display: flex;
@@ -1164,6 +1176,7 @@ code {
.modal-backdrop {
align-items: center;
backdrop-filter: blur(10px);
background: rgb(0 0 0 / 48%);
display: flex;
inset: 0;