Skip to content

Commit 911655e

Browse files
committed
Add a new job view
1 parent 06170b9 commit 911655e

File tree

3 files changed

+144
-38
lines changed

3 files changed

+144
-38
lines changed

frontend/src/routes/batch/ViewBatch.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import Error404 from "../404";
66
import { SetTitleContext } from "../../AppFrame";
77
import { Batch, GET, RepeatURL } from "../../api/api";
88
import InlineSkeletonDisplay from "../../misc/InlineSkeletonDisplay";
9+
import ViewJobs from "../job/ViewJobs";
910

1011
const theme = createTheme();
1112

1213
export default function ViewBatch() {
1314
const { batchId } = useParams<{ batchId: string }>();
1415

15-
const [counter, setCounter] = useState(0);
1616
const setTitle = useContext(SetTitleContext);
1717

1818
const [batch, setBatch] = useState<Batch | null>(null);
@@ -24,17 +24,10 @@ export default function ViewBatch() {
2424
}
2525
GET("/batch/{batch_id}", {
2626
params: { path: { batch_id: Number(batchId) } },
27-
})
28-
.then(({ data }) => {
29-
setBatch(data ?? null);
30-
if (data?.repeat_url && repeatURL === null) {
31-
// No-op
32-
// To-do: GET the repeat URL
33-
}
34-
})
35-
.finally(() => setTimeout(() => setCounter(counter + 1), 10000));
36-
// eslint-disable-next-line react-hooks/exhaustive-deps -- This is a clock function
37-
}, [counter]);
27+
}).then(({ data }) => {
28+
setBatch(data ?? null);
29+
});
30+
}, [batchId]);
3831

3932
useEffect(() => {
4033
setTitle("Batch " + batchId);
@@ -82,6 +75,7 @@ export default function ViewBatch() {
8275
</section>
8376
<section>
8477
<h2>Jobs</h2>
78+
<ViewJobs url={`/job/grid_sort?batch_id=${batchId}`} height="75vh" />
8579
</section>
8680
</div>
8781
);

frontend/src/routes/job/ViewJobs.tsx

Lines changed: 124 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,39 @@ import { DateTime } from "luxon";
1111
import { Job } from "../../api/api";
1212
import BatchChip from "../../misc/BatchChip";
1313

14-
export default function ViewJobs() {
15-
const retColDefs: [
16-
ColDef<Job, number>,
17-
ColDef<Job>,
18-
ColDef<Job, string | null>,
19-
] = [
14+
export default function ViewJobs({ height = "80vh", url = "/job/grid_sort" }) {
15+
const retColDefs: [ColDef<Job, number>, ColDef<Job, string | null>] = [
2016
{
2117
field: "retry",
2218
headerName: "Retries Used",
2319
sortable: true,
24-
filter: true,
25-
},
26-
{
27-
valueGetter: (params) => 4 - (params.data?.retry ?? 0),
28-
headerName: "Retries Left",
29-
sortable: true,
30-
filter: true,
20+
filter: "agMultiColumnFilter",
21+
filterParams: {
22+
filters: [
23+
{
24+
filter: "agNumberColumnFilter",
25+
},
26+
{
27+
filter: "agSetColumnFilter",
28+
},
29+
],
30+
},
3131
},
3232
{
3333
field: "delayed_until",
3434
headerName: "Delayed Until",
3535
sortable: true,
36-
filter: true,
36+
filter: "agMultiColumnFilter",
37+
filterParams: {
38+
filters: [
39+
{
40+
filter: "agDateColumnFilter",
41+
},
42+
{
43+
filter: "agSetColumnFilter",
44+
},
45+
],
46+
},
3747
},
3848
];
3949
const colDefs: [
@@ -46,13 +56,53 @@ export default function ViewJobs() {
4656
ColDef<Job, string>,
4757
ColDef<Job, number>,
4858
] = [
49-
{ field: "id", headerName: "ID", sortable: true, filter: true },
50-
{ field: "url", headerName: "URL", sortable: true, filter: true },
59+
{
60+
field: "id",
61+
headerName: "ID",
62+
sortable: true,
63+
filter: "agMultiColumnFilter",
64+
filterParams: {
65+
filters: [
66+
{
67+
filter: "agNumberColumnFilter",
68+
},
69+
{
70+
filter: "agSetColumnFilter",
71+
},
72+
],
73+
},
74+
},
75+
{
76+
field: "url",
77+
headerName: "URL",
78+
sortable: true,
79+
filter: "agMultiColumnFilter",
80+
filterParams: {
81+
filters: [
82+
{
83+
filter: "agTextColumnFilter",
84+
},
85+
{
86+
filter: "agSetColumnFilter",
87+
},
88+
],
89+
},
90+
},
5191
{
5292
field: "batches",
5393
headerName: "Batches",
54-
sortable: true,
55-
filter: true,
94+
sortable: false,
95+
filter: "agMultiColumnFilter",
96+
filterParams: {
97+
filters: [
98+
{
99+
filter: "agNumberColumnFilter",
100+
},
101+
{
102+
filter: "agSetColumnFilter",
103+
},
104+
],
105+
},
56106
cellRenderer(params: ICellRendererParams<Job, number[] | undefined>) {
57107
return (params.value ?? []).map((batchId) => (
58108
<>
@@ -66,7 +116,17 @@ export default function ViewJobs() {
66116
field: "completed",
67117
headerName: "Archive URL",
68118
sortable: true,
69-
filter: true,
119+
filter: "agMultiColumnFilter",
120+
filterParams: {
121+
filters: [
122+
{
123+
filter: "agDateColumnFilter",
124+
},
125+
{
126+
filter: "agSetColumnFilter",
127+
},
128+
],
129+
},
70130
cellRenderer(params: ICellRendererParams<Job, string | null>) {
71131
if (params.value === null || params.value === undefined) {
72132
return null;
@@ -78,7 +138,22 @@ export default function ViewJobs() {
78138
return <a href={archiveURLString}>{archiveURLString}</a>;
79139
},
80140
},
81-
{ field: "failed", headerName: "Failed At", sortable: true, filter: true },
141+
{
142+
field: "failed",
143+
headerName: "Failed At",
144+
sortable: true,
145+
filter: "agMultiColumnFilter",
146+
filterParams: {
147+
filters: [
148+
{
149+
filter: "agDateColumnFilter",
150+
},
151+
{
152+
filter: "agSetColumnFilter",
153+
},
154+
],
155+
},
156+
},
82157
{
83158
headerName: "Retries",
84159
children: retColDefs,
@@ -87,19 +162,44 @@ export default function ViewJobs() {
87162
field: "created_at",
88163
headerName: "Created At",
89164
sortable: true,
90-
filter: true,
165+
filter: "agMultiColumnFilter",
166+
filterParams: {
167+
filters: [
168+
{
169+
filter: "agDateColumnFilter",
170+
},
171+
{
172+
filter: "agSetColumnFilter",
173+
},
174+
],
175+
},
176+
},
177+
{
178+
field: "priority",
179+
headerName: "Priority",
180+
sortable: true,
181+
filter: "agMultiColumnFilter",
182+
filterParams: {
183+
filters: [
184+
{
185+
filter: "agNumberColumnFilter",
186+
},
187+
{
188+
filter: "agSetColumnFilter",
189+
},
190+
],
191+
},
91192
},
92-
{ field: "priority", headerName: "Priority", sortable: true, filter: true },
93193
];
94194

95195
return (
96-
<div className="ag-theme-quartz" style={{ height: "80vh" }}>
196+
<div className="ag-theme-quartz" style={{ height }}>
97197
<AgGridReact
98198
rowModelType="serverSide"
99199
columnDefs={colDefs}
100200
serverSideDatasource={{
101201
getRows(params: IServerSideGetRowsParams<Job>) {
102-
fetch("/job/grid_sort", {
202+
fetch(url, {
103203
body: JSON.stringify(params.request),
104204
method: "POST",
105205
headers: {

src/routes/job/grid_sort.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
from typing import Iterable
22
from ...main import app, async_session
3-
from ...models import Job
3+
from ...models import URL, Batch, Job
44
from sqlalchemy import select
55
import sqlalchemy.orm
66

77
from . import JobReturn
88

99
from ...server_side_grid import IServerSideGetRowsRequest, LoadSuccessParams
1010

11+
sort_map = {"url": URL.url}
12+
1113

1214
@app.post("/job/grid_sort")
1315
async def get_job_grid_sort(
14-
request: IServerSideGetRowsRequest,
16+
request: IServerSideGetRowsRequest, batch_id: int | None = None
1517
) -> LoadSuccessParams[JobReturn]:
1618
"""Get job grid sort."""
1719

@@ -24,7 +26,17 @@ async def get_job_grid_sort(
2426
.offset(offset)
2527
.limit(limit)
2628
)
29+
if request.sortModel:
30+
for sort in request.sortModel:
31+
sort_attribute = sort_map.get(sort.colId, None) or getattr(Job, sort.colId)
32+
if sort.sort == "asc":
33+
query = query.order_by(sort_attribute)
34+
else:
35+
query = query.order_by(sort_attribute.desc())
2736
count_query = select(sqlalchemy.func.count(Job.id))
37+
if batch_id:
38+
query = query.where(Job.batches.any(Batch.id == batch_id))
39+
count_query = count_query.where(Job.batches.any(Batch.id == batch_id))
2840
async with async_session() as session, session.begin():
2941
data: Iterable[Job] = await session.scalars(query)
3042
result = [JobReturn.from_job(row) for row in data.unique()]

0 commit comments

Comments
 (0)